TRust-DNS (0.10.1)

There is a breaking change coming in TRust-DNS in 0.10.0. I wanted to post here about it in case there are any users that may have a dependency on the client library. I had initially deprecated the old synchronous client in favor of people using the tokio based client instead. After reaching out to a few users, I realized that keeping a synchronous client for ease of use is probably going to be best.

What is changing is that I'm dropping the old implementation of the Client and replacing it with trait based implementations over ClientFuture. There are two impls for the Client trait: SyncClient and SecureSyncClient.

The Client trait has a compatible interface with the old Client, example of query(...):

fn query(&self,
         name: &Name,
         query_class: DNSClass,
         query_type: RecordType)
         -> ClientResult<Message>

and the new version:

fn query(&self,
         name: &Name,
         query_class: DNSClass,
         query_type: RecordType)
         -> ClientResult<Message> { ... }

Those are identical! But to use them you either need to use it with either the new SyncClient or the SecureSyncClient, that is there will be a compile time failure and you'll need to switch to use one of these new variants. The secure variant implements DNSSec extensions, and validates records via DNSSec (only returning verified records). The SecureSyncClient is the variant that implements:

#[deprecated]
fn secure_query(&self,
                query_name: &Name,
                query_class: DNSClass,
                query_type: RecordType)
                -> ClientResult<Message>

So if you used that function, you'll need the SecureSyncClient. A warning though, SecureSyncClient enables DNSSec on both query(...) and secure_query(...) which is a change from the original client, where only secure_query(...) would have performed DNSSec validation.

In addition to these changes, the dynamic DNS functions have been updated to take a generic option over an IntoRecordSet trait:

fn create<R>(&self, rrset: R, zone_origin: Name) -> ClientResult<Message> 
where R: IntoRecordSet

This will allow for an entire record set to be used in all dynamic DNS requests, as opposed to the original which only allowed for a single Record. This should be 100% backward compatible, with the caveat from above of using the new Client variants.

You can see all these changes in the master branch: https://github.com/bluejekyll/trust-dns/blob/master/client/src/client/client.rs

If you're a user and any of these changes look like they'll be issues, please reach out to me ASAP, thanks.

2 Likes

Speaking of breaking changes, would you consider renaming the getter/setter methods in, e.g., rr::resource::Record to be in line with RFC#344? The RFC proposes foo() for a getter, and set_foo() for a setter, whereas TRust-DNS presently uses get_foo() and foo(), respectively.

That's a very disruptive change, I know, and unfortunately there doesn't seem to be a way to introduce it gradually and deprecate the existing methods. Also, I don't really have a well-supported case for the change, aside from the personal experience of revisiting some code using those methods after a few weeks, and being momentarily but powerfully confused by the use of foo() as a setter until I remembered the convention in use; I must have internalized the RFC's recommendations.

Yes, I'd be open to this. That is some of my older, and more juvenile Rust code, in the project. I'm not even consistent everywhere, I've wanted to clean this up.

Maybe this is a good opportunity to make that change, as people will need to update integrations anyway.

I've been considering moving towards a builder pattern in more places anyway. Any preference?

Great! I've opened a PR with the client-side refactoring. The changes are massive but boring; a rustfmt pass would probably be in order.

I don't have a strong preference. IME, the builder pattern works best when the default object can be constructed with good defaults, but subsequently modified in numerous small ways which are difficult to categorize.

1 Like

Sweet. Thanks for the change! Just merged.

I'm working on a separate change, I can do any rustfmt as necessary.

I have some changes coming in 0.10.1 related to TLS.

The initial implementation of TLS was done with native-tls, this had some issues, as OpenSSL is basically required for DNSSec operations at this point. Until I get that abstracted out, I've defaulted the TLS implementation on the server and client to use tokio-openssl instead for consistency. For anyone who is relying on native-tls (I kind of doubt there are many at this point), I'll be moving that to a separate crate, with the excellently long name of trust-dns-native-tls (this is a client side crate, not server). For now, the server will require OpenSSL.

I expect this won't effect many since DNS over TLS isn't widely deployed.

If there are any other minor changes people want in 0.10.1, please file issues in the repo!

This fixes a bug in SIG0 signing and also adds two new crates. There is also a new compatibility test suite for validating the TRust-DNS client (query and update) against BIND with SIG0. Also adds new support for AppVeyor tests.

The new crates:

https://crates.io/crates/trust-dns-rustls
https://crates.io/crates/trust-dns-native-tls

Both give alternative implementations to the TLS client for using rustls and native-tls respectively. The default TLS implementation in TRust-DNS is OpenSSL.

Release notes:

0.10.1

Added

  • Added From<IpAddr> for Name (reverse DNS) #105
  • AppVeyor support #103
  • rustls client tls support (seperate crate)
  • full support for KEY RR in client
  • compatibility tests with BIND for SIG0 updates
  • Added full implementation of KEY type

Changed

  • Updated TLS documentation, added more elsewhere, docs required; fixes #102
  • Upgraded tokio-core and moved to tokio-io
  • Important Some Server types have been migrated to RFC#344 style. get_field() -> field(); field() -> set_field()
  • Moved native-tls client impl to seperate crate
  • Defaulted to OpenSSL for tls implementation

Fixed

  • key_tag calculation for DNSKEY and KEY now correct #118 (@jannic)
  • SIG0 signing fixed to match RFC and BIND #120 (@jannic)
1 Like

Would it be possible to use ring and ring-tls instead of OpenSSL?, or at least to use LibreSSL or BoringSSL? This is mostly for security.

1 Like

TRust-DNS already supports ring and rustls (ring based tls).

See trust_dns_rustls - Rust

For building you'll want to use these features when building: "--no-default-features --features=ring". For examples using see these tests: https://github.com/bluejekyll/trust-dns/blob/master/rustls/src/tests.rs#L69 ... I definitely need more usage docs around all of this, but at least the code is there! :slight_smile:

And then you'd use the trust-dns-rustls library for the TLS library. Note though, I haven't yet added support for validation of RSA or ECDSA DNSSec records with Ring, so you'd lose RSA and ECDSA validation without OpenSSL as it is today. I'm of course open to anyone submitting a PR! An alternative implementation would be needed here:

https://github.com/bluejekyll/trust-dns/blob/master/client/src/rr/dnssec/public_key.rs#L316