nlnetlabs / domain Goto Github PK
View Code? Open in Web Editor NEWA DNS library for Rust.
Home Page: https://nlnetlabs.nl/projects/domain/about/
License: BSD 3-Clause "New" or "Revised" License
A DNS library for Rust.
Home Page: https://nlnetlabs.nl/projects/domain/about/
License: BSD 3-Clause "New" or "Revised" License
Hi, I ended up adding a bunch of helper functions over time as I was updating to the 0.5 domain library, and I thought some of it might be useful in the base library itself. Maybe there's a nicer way of doing this stuff, so I thought I would open this ticket first to see what would make sense / when there's a better way to do things. I'm happy to open PRs for things you thing would be good to add.
/// Creates a root domain over any octets.
pub fn root_name<O>() -> Result<Dname<O>> where O: FromBuilder;
/// Convert name to canonical format (equivalent to "to_dname()" but also converts to canonical format)
pub fn to_canonical_name<O>(name: impl ToDname) -> Dname<O> where O: FromBuilder;
/// Convert OctetsRef into owned Octets.
pub fn to_octets<O, R>(o: R) -> Result<O> O: FromBuilder;
Message<&[u8]>
in cache with a different storage type. I've added this convenience conversion function like this, but it's still a bit tedious. Perhaps some sort of "convert()" method would be useful for all types?/// Convert Record into another Record with different RDATA.
pub fn from_record<N: ToDname, O: FromBuilder, D, DD, F: FnOnce(D) -> Result<DD>>(
rr: Record<N, D>,
f: F,
) -> Result<Record<Dname<O>, DD>>;
std::fmt::Display
. Perhaps that would be useful in the domain library as well?/// Extension for `domain::Message` for pretty printing.
pub trait MessageExt<O> {
/// Formats the message question as a shorthand "<query name> <query_type>".
fn as_formatted_query(&self) -> FmtQuery<O>;
/// Formats the message and records using a dig-like text format.
fn as_formatted_text(&self) -> FmtMessageText<O>;
/// Formats the message and records using a short text format.
fn as_formatted_short(&self) -> FmtMessageShort<O>;
}
Currently, I found myself often writing boilerplate codes around MessageBuilder
to copy existing message records to simply add one records or overwrite the old one.
I think I do understand, for the sake of performance, domain builds the message section by section. However, in real world, this renders above editing scene quite cumbersome. Can we have a more flexible but less performant API on editing messages?
BTW, domain's performance is unparalleled from what I know in the rust on DNS processing. Great work!
This is a great code base (does exactly what I want!) but the example for how to use domain_resolv (domain-resolv/examples/lookup.rs) is misleading.
The CLI accepts multiple addresses and gives the impression that it is going to resolve each of those iteratively. Based on the code, this is not what happens. Only the first of the addresses on the CLI is resolved. The remainder are just dropped.
Is this something that is known? I'd be happy to make changes to the example, if that's something that you would want!
Thanks again for the great tool!
Will
I'm trying to figure out how to do an SRV record lookup. Basically I want to automate detection of a domain controller. I can't figure out the syntax involved here though as it returns an error that my label syntax is incorrect:
let answer = StubResolver::new().lookup_srv(
RelativeDname::from_octets(b"_ldap._tcp").unwrap(),
Dname::<Vec<u8>>::from_str("example.com").unwrap(),
389).await.unwrap();
What is the correct way to provide the service parameter?
Also, is there a way to populate the resolver's search suffix list other than manually filling it in? I'm guessing something involving DHCP is needed but I don't know which options to look for, or if there are any crates out there that can pick it up from all major platforms.
Thanks!
I'm not affiliated with the project, I'm just curious as to why you decided to roll your own DNS library instead of contributing to what's missing in trust-dns instead? For the sake of diversity, or you have completely different goals, or some other reason?
The following program (adapted from the ‘sync’ example in domain-resolv) panics:
use domain::{
base::{name::Dname, Rtype},
rdata::AllRecordData,
};
use domain_resolv::StubResolver;
use std::str::FromStr;
fn main() {
let name = Dname::<Vec<_>>::from_str("imsavscan.netvigator.com").unwrap();
let res = StubResolver::run(move |stub| async move {
stub.query((name, Rtype::A)).await
});
let res = res.unwrap();
let res = res.answer().unwrap().limit_to::<AllRecordData<_, _>>();
for record in res {
let record = record.unwrap();
println!("{}", record);
}
}
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ShortInput', src/main.rs:18:22
It’s just a query for A records of domain imsavscan.netvigator.com
.
It looks like the answer contains defective records? However, other DNS resolvers that I have tried do not indicate an error with this query, so I’m wondering if this could be a bug in domain-resolv? I could not investigate further, apologies for the simple bug report.
I'll try to look into this, unless someone is already tackling this.
On embedded targets, stack space might be rather limited.
In a concrete case, size optimized code that creates, processes and returns a 512 byte buffer overflowed a 5k stack. As a workaround, I've been able to implement OctetsBuilder
for &mut heapless::Vec<u8, 512>
and pass it to MessageBuilder and the rest of my code. I wonder if this could be implemented in a more general way - either for each OctetsX
type, or in a different manner.
Currently the cookie struct can only store a client cookie:
pub struct Cookie([u8; 8]);
It should also be able to store the complete cookie (client+server) and be able to differentiate between those two.
How do you want to handle building Update messages? Should it be part of MessageBuilder? Should there be a separate UpdateBuilder?
There are places in the code like:
let len = (self.target.len() - 2) as u16;
This bogusly truncates the length when it is more than 16 bits. These should be changed to try_from
I could write a patch if it helps.
Plenty of error types are currently public enums. This leads to the necessity of breaking changes any time their content needs to be adjusted. Instead, we should use private enums inside newtypes.
I got the following panic:
thread 'main' panicked at 'attempt to calculate the remainder with a divisor of zero', /usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/domain-0.7.0/src/resolv/stub/mod.rs:709:15
Looks like this line is problematic:
Lines 708 to 710 in 4fb8fb0
I haven't had time to dig into it, but I can take a look next week.
This is more a weak suggestion or a question, feel free to close. I’m
using domain-resolv in a library that does not use async Rust, it only
does synchronous DNS resolution. That library is meant for long-running
programs, and will repeatedly invoke StubResolver::run
.
As far as I understand, StubResolver::run
is not meant to be used in
this way, as it has a per-call overhead of instantiating an async
runtime etc.
As a consequence, non-async consumers of domain-resolv have to create
and manage an async runtime themselves, and have to depend directly on
async packages like tokio, even though they are not themselves actually
async libraries or applications.
The question for me is whether the state of affairs described above is
as-designed, or whether the ‘story’ for synchronous consumers could be
fleshed out, in the sense that consumers would be able to use
domain-resolv without requiring any knowledge or dependencies on async
Rust. I note that I am not an expert user, that is, my interest is in a
simple and easy-to-use synchronous DNS resolution facility (use case is
SPF protocol).
Thank you.
Looking at the docs page in doc/domain_core/bits/message/struct.RecordSection.html and found some issues. ParseRecord probably should be ParsedRecord and into_record() doesn't seem to link anywhere.
For our use case, we're forwarding some requests to an unbound
server running on our hosts.
The StubResolver
doesn't quite work for us because:
Message
as the query, only a impl Question
, therefore the response's id
won't match our request's id
.Message
(from Answer::into_message
) because the underlying Octets
are Bytes
which aren't mutable.We presently work around this by writing the answer's bytes to a BytesMut
, then using that as a Message
's backing Octets
and then modifying the header to set the original request's id
.
Would it be desirable to add a function to make a DNS request via a full Message
instead of just impl Question
?
If not, then maybe a query_mut
function to receive an Answer
that can be converted to a Message<BytesMut>
.
Hello,
I am total newbie in Rust attempting to use domain library. But I have found a lot blockers. Is there a good electronic channel, where I could ask for help with my little project? I guess I would have multiple questions, but I don't think I should use issues here. They are not issues in library itself. They relate just to my inability to use the library in my own application. I find fiddling with domain names and creating raw query with asynchronous lookup hard.
Where can I ask more experimenced people about this library?
Using domain 0.4 on machos, it always fails.
To reproduce it is enough to use an example from domain-resolve/examples/downloader.rs.
Finished dev [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/dtest`
thread 'tokio-runtime-worker-0' panicked at 'called Option::unwrap()
on a None
value', src/libcore/option.rs:345:21
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:39
1: std::sys_common::backtrace::_print
at src/libstd/sys_common/backtrace.rs:70
2: std::panicking::default_hook::{{closure}}
at src/libstd/sys_common/backtrace.rs:58
at src/libstd/panicking.rs:200
3: std::panicking::default_hook
at src/libstd/panicking.rs:215
4: <std::panicking::begin_panic::PanicPayload as core::panic::BoxMeUp>::get
at src/libstd/panicking.rs:478
5: std::panicking::continue_panic_fmt
at src/libstd/panicking.rs:385
6: std::panicking::try::do_call
at src/libstd/panicking.rs:312
7: ::type_id
at src/libcore/panicking.rs:85
8: ::type_id
at src/libcore/panicking.rs:49
9: domain_resolv::stub::resolver::giving_up_error
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libcore/macros.rs:11
10: domain_resolv::stub::resolver::ResolverInner::from_conf::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/domain-resolv-0.4.0/src/stub/resolver.rs:216
11: domain_resolv::stub::resolver::Query::next_server
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/domain-resolv-0.4.0/src/stub/resolver.rs:274
12: domain_resolv::stub::resolver::Query::next_server
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/domain-resolv-0.4.0/src/stub/resolver.rs:331
13: <domain_resolv::lookup::host::MaybeDone>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/domain-resolv-0.4.0/src/lookup/host.rs:173
14: <domain_resolv::lookup::host::LookupHost as futures::future::Future>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/domain-resolv-0.4.0/src/lookup/host.rs:130
15: <futures::future::chain::Chain<A, B, C>>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/chain.rs:26
16: <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/and_then.rs:32
17: <futures::future::chain::Chain<A, B, C>>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/chain.rs:26
18: <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/and_then.rs:32
19: <futures::future::chain::Chain<A, B, C>>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/chain.rs:26
20: <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/and_then.rs:32
21: <futures::future::chain::Chain<A, B, C>>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/chain.rs:26
22: <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/and_then.rs:32
23: <futures::future::chain::Chain<A, B, C>>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/chain.rs:26
24: <futures::future::and_then::AndThen<A, B, F> as futures::future::Future>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/and_then.rs:32
25: <futures::future::chain::Chain<A, B, C>>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/chain.rs:26
26: <futures::future::then::Then<A, B, F> as futures::future::Future>::poll
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/then.rs:32
27: <futures::task_impl::NotifyHandle as core::clone::Clone>::clone
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/future/mod.rs:113
28: std::sys_common::mutex::Mutex::raw_lock
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/task_impl/mod.rs:329
29: std::sys_common::mutex::Mutex::raw_lock
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/task_impl/mod.rs:399
30: futures::task_impl::std::CURRENT_THREAD_NOTIFY::__init
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/task_impl/std/mod.rs:78
31: std::sys_common::mutex::Mutex::raw_lock
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/task_impl/mod.rs:399
32: std::sys_common::mutex::Mutex::raw_lock
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/task_impl/mod.rs:291
33: std::sys_common::mutex::Mutex::raw_lock
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.26/src/task_impl/mod.rs:329
34: tokio_threadpool::task::Task::run::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/task/mod.rs:145
35: core::ops::function::FnOnce::call_once
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libcore/ops/function.rs:231
36: core::ptr::swap_nonoverlapping_bytes
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/panic.rs:309
37: crossbeam_utils::backoff::Backoff::snooze
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/panicking.rs:297
38: panic_unwind::dwarf::eh::read_encoded_pointer
at src/libpanic_unwind/lib.rs:87
39: crossbeam_utils::backoff::Backoff::snooze
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/panicking.rs:276
40: crossbeam_utils::backoff::Backoff::snooze
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/panic.rs:388
41: tokio_threadpool::task::Task::run
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/task/mod.rs:130
42: tokio_threadpool::worker::Worker::run_task2
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/worker/mod.rs:567
43: tokio_threadpool::worker::Worker::run_task
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/worker/mod.rs:459
44: tokio_threadpool::worker::Worker::try_run_owned_task
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/worker/mod.rs:390
45: tokio_threadpool::worker::Worker::try_run_task
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/worker/mod.rs:297
46: tokio_threadpool::worker::Worker::with_current::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/worker/mod.rs:241
47: tokio::runtime::threadpool::builder::Builder::build::{{closure}}::{{closure}}::{{closure}}::{{closure}}::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.19/src/runtime/threadpool/builder.rs:349
48: futures::task_impl::std::CURRENT_THREAD_NOTIFY::__init
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-trace-core-0.1.0/src/dispatcher.rs:54
49: tokio::runtime::threadpool::builder::Builder::build::{{closure}}::{{closure}}::{{closure}}::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.19/src/runtime/threadpool/builder.rs:348
50: <tokio_reactor::HandlePriv as core::clone::Clone>::clone
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-timer-0.2.10/src/timer/handle.rs:94
51: alloc::raw_vec::alloc_guard
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:300
52: alloc::raw_vec::alloc_guard
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:246
53: <tokio_reactor::HandlePriv as core::clone::Clone>::clone
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-timer-0.2.10/src/timer/handle.rs:81
54: tokio::runtime::threadpool::builder::Builder::build::{{closure}}::{{closure}}::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.19/src/runtime/threadpool/builder.rs:347
55: futures::task_impl::core::get_ptr
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-timer-0.2.10/src/clock/clock.rs:141
56: alloc::raw_vec::alloc_guard
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:300
57: alloc::raw_vec::alloc_guard
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:246
58: futures::task_impl::core::get_ptr
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-timer-0.2.10/src/clock/clock.rs:124
59: tokio::runtime::threadpool::builder::Builder::build::{{closure}}::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.19/src/runtime/threadpool/builder.rs:346
60: alloc::raw_vec::alloc_guard
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-reactor-0.1.9/src/lib.rs:237
61: alloc::raw_vec::alloc_guard
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:300
62: alloc::raw_vec::alloc_guard
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:246
63: alloc::raw_vec::alloc_guard
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-reactor-0.1.9/src/lib.rs:217
64: tokio::runtime::threadpool::builder::Builder::build::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.19/src/runtime/threadpool/builder.rs:345
65: tokio_threadpool::callback::Callback::call
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/callback.rs:22
66: tokio_threadpool::worker::Worker::do_run::{{closure}}::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/worker/mod.rs:127
67: <tokio_threadpool::task::blocking::State as core::cmp::PartialEq>::eq
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-executor-0.1.7/src/global.rs:209
68: std::sys::unix::mutex::Mutex::destroy
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:300
69: std::sys::unix::mutex::Mutex::destroy
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:246
70: <tokio_threadpool::task::blocking::State as core::cmp::PartialEq>::eq
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-executor-0.1.7/src/global.rs:178
71: tokio_threadpool::worker::Worker::do_run::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/worker/mod.rs:125
72: std::sys::unix::mutex::Mutex::destroy
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:300
73: std::sys::unix::mutex::Mutex::destroy
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/local.rs:246
74: tokio_threadpool::worker::Worker::do_run
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/worker/mod.rs:116
75: tokio_threadpool::pool::Pool::spawn_thread::{{closure}}
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-threadpool-0.1.14/src/pool/mod.rs:344
76: crossbeam_epoch::collector::LocalHandle::is_pinned
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/sys_common/backtrace.rs:135
77: crossbeam_epoch::default::is_pinned
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/mod.rs:469
78: core::ptr::swap_nonoverlapping_bytes
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/panic.rs:309
79: crossbeam_utils::backoff::Backoff::snooze
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/panicking.rs:297
80: panic_unwind::dwarf::eh::read_encoded_pointer
at src/libpanic_unwind/lib.rs:87
81: crossbeam_utils::backoff::Backoff::snooze
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/panicking.rs:276
82: crossbeam_utils::backoff::Backoff::snooze
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/panic.rs:388
83: crossbeam_epoch::default::is_pinned
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/thread/mod.rs:468
84: core::alloc::Layout::repeat
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/liballoc/boxed.rs:749
85: std::sys::unix::thread::Thread::new::thread_start
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/liballoc/boxed.rs:759
at src/libstd/sys_common/thread.rs:14
at src/libstd/sys/unix/thread.rs:81
86: _pthread_body
87: _pthread_start
thread 'main' panicked at 'called Result::unwrap()
on an Err
value: Canceled', src/libcore/result.rs:997:5
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:39
1: std::sys_common::backtrace::_print
at src/libstd/sys_common/backtrace.rs:70
2: std::panicking::default_hook::{{closure}}
at src/libstd/sys_common/backtrace.rs:58
at src/libstd/panicking.rs:200
3: std::panicking::default_hook
at src/libstd/panicking.rs:215
4: <std::panicking::begin_panic::PanicPayload as core::panic::BoxMeUp>::get
at src/libstd/panicking.rs:478
5: std::panicking::continue_panic_fmt
at src/libstd/panicking.rs:385
6: std::panicking::try::do_call
at src/libstd/panicking.rs:312
7: ::type_id
at src/libcore/panicking.rs:85
8: core::result::unwrap_failed
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libcore/macros.rs:17
9: <core::result::Result<T, E>>::unwrap
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libcore/result.rs:798
10: tokio::runtime::threadpool::Runtime::block_on
at /Users/ermine/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.1.19/src/runtime/threadpool/mod.rs:266
11: dtest::main
at src/main.rs:54
12: std::rt::lang_start::{{closure}}
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/rt.rs:64
13: std::panicking::try::do_call
at src/libstd/rt.rs:49
at src/libstd/panicking.rs:297
14: panic_unwind::dwarf::eh::read_encoded_pointer
at src/libpanic_unwind/lib.rs:87
15: std::panicking::update_count_then_panic
at src/libstd/panicking.rs:276
at src/libstd/panic.rs:388
at src/libstd/rt.rs:48
16: std::rt::lang_start
at /rustc/fc50f328b0353b285421b8ff5d4100966387a997/src/libstd/rt.rs:64
17: dtest::main
I think stub resolver does not provide any way to modify message of question. It does not allow any customization of outgoing messages. resolv/stub/mod.rs contains create_message. That sets recursion disabled always, even when there is recursion flag in options. I have not found documented way to obtain nameservers parsed from current StubResolver. Only options. Is that intentional?
I wanted to detect, whether the server strips out EDNS or DO flag in OPT section. OPT section is accessible in answer, but I haven't found any trace to put it also into question. Am I wrong?
https://github.com/bluejekyll/trust-dns
Contains both libraries and binaries. Implements different transports. Seems quite fleshed out.
Also has done a fair bit of performance optimization: https://bluejekyll.github.io/blog/rust/2017/12/29/making-trust-dns-fast.html
There are also some other Trust DNS related blog posts the author has written that you may want to try out.
According to Section 18.14 of RFC 6762, name compression can happen in the RDATA of the following record types:
NS, CNAME, PTR, DNAME, SOA, MX, AFSDB, RT, KX, RP, PX, SRV, NSEC
Looks like there is a problem with code conditional on some Cargo feature.
On current main
(commit b10fc8b):
cargo run --features resolv --example lookup -- crates.io
error[E0412]: cannot find type `Bytes` in this scope
--> src/rdata/rfc5155.rs:618:16
|
618 | impl Nsec3Salt<Bytes> {
| ^^^^^ not found in this scope
|
help: consider importing one of these items
|
7 | use bytes::Bytes;
|
7 | use core::str::Bytes;
|
7 | use crate::rdata::rfc5155::str::Bytes;
|
7 | use std::io::Bytes;
|
and 1 other candidate
...
...
There is probably a way to catch this and similar issues at the CI build stage.
Primary focus here is to finalize the structure of Scan
trait so that we can add more record types without the risk of having to re-write everything again.
For requirements, also see #105.
I'll be needing TSIG support for Update. I'll be glad to add this feature but I'll need some coaching. Can you point me in the right direction?
I would love to use this library for a small educational name server I am working on, however the API does not quite seem to cover my use case (yet? :). I want to provide a command-line interface to add records while the server is running, e.g:
myclient example.com add mx 10 alt1.example.com.
The only provided API to parse MasterRecordData
from a human friendly string seems to be MasterRecordData::scan()
, powered by the Scan
trait of the experimental master
module. While attempting to use this API, I stumbled upon several issues:
x
as MX data yields unexpected 'x'
, it would be nice to tell the user what was expected (numeric MX priority)99999
as MX data yields illegal integer
, it would be nice to tell the user why the integer is illegal (priority may not be greater than 65535)unespected end of file
doesn't tell you what was expectedScan
trait isn't suited to parse command-line arguments since Scanner assumes the context of a Zone file.
10 foo
as MX data yields owner @ without preceding $ORIGIN
(which I'd argue is confusing even in a zone file but is of course completely out of place for command-line arguments)TXT
records can contain arbitrary binary data, I want users to be able to directly provide an arbitrary TXT value as a command-line argument (which don't need to be UTF-8).So I think it would be great if this library could somehow support both parsing records from zone files as well as parsing them from e.g. an Iterator<Item=OsString>
(where each item represents one part of the record data).
I guess this could be achieved by changing the Scan
trait, that record data types implement, to take a new Scanner
trait (instead of a zone-specific scanner). I am not quite sure yet how this Scanner
trait would look like exactly but I think it would need to abstract over the zone-file specifics like $ORIGIN
, by e.g. having a scan_absolute_name(&mut self) -> Result<Dname, ScanError>
method.
Do you think this is worth pursuing?
Looking at the lookups implementation, I see that the result iterators all take care to only return records where the owner matches the canonical name of the answer (?). For example:
domain/src/resolv/lookup/host.rs
Line 191 in 8820610
I am currently using StubResolver
to perform queries without filtering like this, and it seems to be working well. Surely I’m missing some basic thing about DNS. Could you explain why this filtering is necessary? Thank you.
The docs lists a bunch of feature flags that have been removed or merged with others. I think it may not have been updated when those changes happened, although I can't be sure because the list seems long untouched.
What's especially interesting to me is that the docs mention feature flags that have the same name as dependencies, which should have never worked as far as I can understand. Quoting the cargo book:
Note: A feature in the [feature] table cannot use the same name as a dependency. Experimental support for enabling this and other extensions is available on the nightly channel via namespaced features.
resolve README lists “querying for raw DNS records“ as a feature but could you add an example for how this is supposed to work? Maybe TXT records would make a good example since they are specifically listed.
If not an example, maybe just some hints in this issue?
tokio brings in a lot of packages and all the resolver really needs is a way to do async io. mio does this and it might be better to use it directly than depend on tokio.
Just noticed the extra target
dir when cleaning up after my PRs.
The files are (relative to Cargo.toml
when executing cargo test --all-features
):
../target/test/tsig_client_nsd/nsd.conf
../target/test/tsig_client_sequence_nsd/nsd.conf
I wonder if this is because I do not have the nsd
binary installed?
Is it true that the stub resolver does not currently support the ‘authentic data’ flag? Like dig +adflag
? Or could you explain how to access this flag?
If it isn’t available yet, then please consider this a feature request.
Thank you.
Hello 👋 do you have any immediate plans for supporting DoT / DoH in the stub resolver?
$ target/debug/examples/lookup example.org
Found answer for example.org
example.org has address 2606:2800:220:1:248:1893:25c8:1946
example.org has address 93.184.216.34
$ target/debug/examples/lookup 93.184.216.34
$ target/debug/examples/lookup 2606:2800:220:1:248:1893:25c8:1946
thread 'main' panicked at 'internal error: entered unreachable code', src/resolv/lookup/addr.rs:137:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I might be missing something, but we're having to write a lot more code than I think necessary in our tests to fashion an impl ToDname
.
In our app, we have a function that takes a ParsedDname<&Bytes>
because that's what we get from a Question::qname()
call from a Message<Bytes>
.
Now, to get an impl ToDname
from scratch (without manually writing out the bytes with the length of each label, which is tedious), there are 2 options as far as I can see:
Dname::bytes_from_str(&str) -> Result<Dname<Bytes>, FromStrError>
This would be the easiest! Except that's not what the function we want to test expects. There's Dname::into
that can return a ParsedDname<Bytes>
, but we need a ParsedDname<&Bytes>
.
Doing the above, but re-parsing the bytes:
let dname = Dname::bytes_from_str("example.com").unwrap();
let mut parser = Parser::from_ref(dname.as_octets());
let question = Question::new_in(ParsedDname::parse(&mut parser).unwrap(), Rtype::A);
Is there a better way to do this?
This is not a big deal, we can abstract this out. This is only used in our tests, but I feel like it could be better ergonomically.
The SRV record's target field is a domain name. However, it must not be compressed, so it’s Compress
implementation must fall back to composing.
RFC 8427 defines a JSON representations for DNS messages and their components. We already have some Serde serialization in domain, but it isn’t quite complete and doesn’t always match the definition in the RFC.
Adjust what’s there already and a add what’s missing so that all serialization follows the representation defined by the RFC.
Now that there is a separate domain::core
crate, it feels like the bits
module is an unnecessary extra indirection and could be dropped, merging all its contents into domain::core
directly.
This would require some changes in use
statements all over the code using domain::core
. As a mitigation, we could keep bits
for a while and re-export what already is in there now.
This might not be a bug, but it's perhaps surprising that the stub resolver doesn't fail over to TCP on truncation unless there's TCP explicitly added in the ResolvConf::servers. I would assume that adding a server with protocol UDP means you prefer to talk to that server over UDP, but failover on truncation would work. Similarly, if you add a server with protocol TCP it means you prefer to talk to server over TCP and there failover on truncation doesn't apply. I am happy to add a PR but thought I would open a ticket first to get your input on what would be the best way to solve this. I would probably make the failover to TCP on TC automatic with no changes to the API, but it would also work if you added something like Protocol::UdpOrTcp
or convey this through some other way.
Add the following block to Cargo.toml
:
[dependencies.domain]
default-features = false
features = ["tsig"]
version = "^0.7"
Compile. The result is an error:
error[E0433]: failed to resolve: use of undeclared crate or module `std`
--> /home/XXX/.cargo/registry/src/github.com-1ecc6299db9ec823/domain-0.7.0/src/tsig/mod.rs:71:5
|
71 | use std::collections::HashMap;
| ^^^ use of undeclared crate or module `std`
error[E0432]: unresolved import `std`
--> /home/XXX/.cargo/registry/src/github.com-1ecc6299db9ec823/domain-0.7.0/src/tsig/mod.rs:72:5
|
72 | use std::{cmp, error, fmt, hash, mem, str};
| ^^^ use of undeclared crate or module `std`
error[E0433]: failed to resolve: use of undeclared crate or module `std`
--> /home/XXX/.cargo/registry/src/github.com-1ecc6299db9ec823/domain-0.7.0/src/tsig/mod.rs:1342:18
|
1342 | impl<'a, Octets> std::ops::Deref for MessageTsig<'a, Octets>
| ^^^ use of undeclared crate or module `std`
If tsig
is intended to require std
, it should probably declare such a dependency in domain
’s Cargo.toml
. If not, these errors should be fixed.
Hi,
I'm looking into adding support for SPF to domain. I've seen that TXT records are already supported. I think it would be great if domain could serialize and deserialize SPF records according to RFC7208.
I'm planning to create a tool to check SPF records. However, I think serializing / deserializing SPF records should be placed in domain.
Looking at the code structure of domain, I guess the approach would be to add a module rdata::rfc7208 which relies on rdata::rfc1035::Txt.
Let me know what you think.
It fails with:
error[E0432]: unresolved import
--> src/main.rs:9:18
|
9 | use domain_core::name::UncertainDname;
| ^^^^ could not find `name` in `domain_core`
I'm compiling against domain 0.4.0.
The functionality provided by the octets module is not limited to DNS data processing. Perhaps it may be useful to move it into its own crate so that other project can use it (and perhaps improve it) as well?
Any opinions?
Hey,
I'm not 100% sure why this fails, but when trying to do the following I receive the error:
Error:
error[E0277]: `dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>` cannot be sent between threads safely
--> examples\lookup-runtime.rs:13:13
|
13 | runtime.spawn(real_main());
| ^^^^^ `dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>`
= note: required because of the requirements on the impl of `Send` for `Unique<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>`
= note: required because it appears within the type `Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>`
= note: required because it appears within the type `Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>`
= note: required because it appears within the type `tokio::future::maybe_done::MaybeDone<Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>>`
= note: required because it appears within the type `(tokio::future::maybe_done::MaybeDone<Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>>, tokio::future::maybe_done::MaybeDone<Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>>)`
= note: required because it appears within the type `for<'r> {ResumeTy, &'r &StubResolver, domain::base::Dname<Vec<u8>>, (tokio::future::maybe_done::MaybeDone<Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>>, tokio::future::maybe_done::MaybeDone<Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>>), [closure@domain::resolv::lookup::lookup_host<&StubResolver, domain::base::Dname<Vec<u8>>>::{closure#0}::{closure#0}], tokio::future::poll_fn::PollFn<[closure@domain::resolv::lookup::lookup_host<&StubResolver, domain::base::Dname<Vec<u8>>>::{closure#0}::{closure#0}]>, ()}`
= note: required because it appears within the type `[static generator@domain::resolv::lookup::lookup_host<&StubResolver, domain::base::Dname<Vec<u8>>>::{closure#0} for<'r> {ResumeTy, &'r &StubResolver, domain::base::Dname<Vec<u8>>, (tokio::future::maybe_done::MaybeDone<Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>>, tokio::future::maybe_done::MaybeDone<Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>>), [closure@domain::resolv::lookup::lookup_host<&StubResolver, domain::base::Dname<Vec<u8>>>::{closure#0}::{closure#0}], tokio::future::poll_fn::PollFn<[closure@domain::resolv::lookup::lookup_host<&StubResolver, domain::base::Dname<Vec<u8>>>::{closure#0}::{closure#0}]>, ()}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@domain::resolv::lookup::lookup_host<&StubResolver, domain::base::Dname<Vec<u8>>>::{closure#0} for<'r> {ResumeTy, &'r &StubResolver, domain::base::Dname<Vec<u8>>, (tokio::future::maybe_done::MaybeDone<Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>>, tokio::future::maybe_done::MaybeDone<Pin<Box<dyn Future<Output = std::result::Result<domain::resolv::stub::Answer, std::io::Error>>>>>), [closure@domain::resolv::lookup::lookup_host<&StubResolver, domain::base::Dname<Vec<u8>>>::{closure#0}::{closure#0}], tokio::future::poll_fn::PollFn<[closure@domain::resolv::lookup::lookup_host<&StubResolver, domain::base::Dname<Vec<u8>>>::{closure#0}::{closure#0}]>, ()}]>`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2> {ResumeTy, &'r StubResolver, domain::base::Dname<Vec<u8>>, &'s &'t0 StubResolver, impl Future, ()}`
= note: required because it appears within the type `[static generator@StubResolver::lookup_host<domain::base::Dname<Vec<u8>>>::{closure#0} for<'r, 's, 't0, 't1, 't2> {ResumeTy, &'r StubResolver, domain::base::Dname<Vec<u8>>, &'s &'t0 StubResolver, impl Future, ()}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@StubResolver::lookup_host<domain::base::Dname<Vec<u8>>>::{closure#0} for<'r, 's, 't0, 't1, 't2> {ResumeTy, &'r StubResolver, domain::base::Dname<Vec<u8>>, &'s &'t0 StubResolver, impl Future, ()}]>`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `for<'r, 's> {ResumeTy, StubResolver, domain::base::Dname<Vec<u8>>, impl Future, ()}`
= note: required because it appears within the type `[static generator@examples\lookup-runtime.rs:16:22: 21:2 for<'r, 's> {ResumeTy, StubResolver, domain::base::Dname<Vec<u8>>, impl Future, ()}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@examples\lookup-runtime.rs:16:22: 21:2 for<'r, 's> {ResumeTy, StubResolver, domain::base::Dname<Vec<u8>>, impl Future, ()}]>`
= note: required because it appears within the type `impl Future`
= note: required because it appears within the type `impl Future`
Example:
use domain::base::name::UncertainDname;
use domain::resolv::StubResolver;
use domain::base::Dname;
use std::str::FromStr;
fn main() {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build().expect("failed to create runtime");
runtime.spawn(real_main());
}
async fn real_main() {
let resolver = StubResolver::new();
let address = Dname::<Vec<u8>>::from_str("example.com").expect("failed to parse test address");
resolver.lookup_host(address).await;
}
I'm not sure if I'm overlooking anything.
Do I need to generate the documentation locally for modules which are disabled by default?
After actually having used tokio’s new approach of using features atop a single crate rather than minimalist sub-crates, I wonder if maybe we should do the same thing for domain.
I.e., there’d be only one domain crate that contains the various sub-crates such as domain-resolv as an opt-in feature, e.g. "resolv"
.
The upcoming 0.5 with loads of breaking changes would be a good time to do that.
Any opinions on this?
I'd find it useful if there was a single struct containing the flags from the message header. It'd also be useful if it had a text representation, e.g. "QR AA" and if the struct could be constructed from this string representation as well.
I'd use the same string representation as the dnspython library: https://github.com/rthalley/dnspython/blob/master/dns/flags.py
For now, I'd stick with standard flags only (ignoring EDNS flags), which can be easily constructed from header.
Would this feature make sense to you? If so, I could contribute the code.
Compiling domain-resolv-preview v0.3.1 (https://github.com/NLnetLabs/domain-core.git#c0463de8)
error[E0432]: unresolved import `futures_util::compat::TokioDefaultSpawn`
--> /Users/pusateri/.cargo/git/checkouts/domain-core-5d0a0b48f993e038/c0463de/domain-resolv/src/resolver.rs:16:5
|
16 | use futures_util::compat::TokioDefaultSpawn;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `TokioDefaultSpawn` in `compat`. Did you mean to use `TokioDefaultSpawner`?
error[E0061]: this function takes 0 parameters but 1 parameter was supplied
--> /Users/pusateri/.cargo/git/checkouts/domain-core-5d0a0b48f993e038/c0463de/domain-resolv/src/resolver.rs:135:44
|
135 | op(&resolver).boxed().unit_error().compat(TokioDefaultSpawn)
| ^^^^^^ expected 0 parameters
error: aborting due to 2 previous errors
Some errors occurred: E0061, E0432.
For more information about an error, try `rustc --explain E0061`.
error: Could not compile `domain-resolv-preview`.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.