[GH-ISSUE #2058] How can AsyncClient be used with UdpStream? #865

Open
opened 2026-03-16 00:38:09 +03:00 by kerem · 11 comments
Owner

Originally created by @qjmiao on GitHub (Oct 12, 2023).
Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/2058

Are there any examples on AsyncClient being used with UdpStream?

Originally created by @qjmiao on GitHub (Oct 12, 2023). Original GitHub issue: https://github.com/hickory-dns/hickory-dns/issues/2058 Are there any examples on AsyncClient being used with UdpStream?
Author
Owner

@djc commented on GitHub (Oct 12, 2023):

What are you trying to do? For most use cases, the -resolver crate might be more appropriate than the -client crate.

<!-- gh-comment-id:1759286315 --> @djc commented on GitHub (Oct 12, 2023): What are you trying to do? For most use cases, the -resolver crate might be more appropriate than the -client crate.
Author
Owner

@qjmiao commented on GitHub (Oct 12, 2023):

What are you trying to do? For most use cases, the -resolver crate might be more appropriate than the -client crate.

I'm trying to use AsyncClient in axum http handler to delete/add dns records from/to bind name server?

<!-- gh-comment-id:1759532526 --> @qjmiao commented on GitHub (Oct 12, 2023): > What are you trying to do? For most use cases, the -resolver crate might be more appropriate than the -client crate. I'm trying to use AsyncClient in axum http handler to delete/add dns records from/to bind name server?
Author
Owner

@djc commented on GitHub (Oct 12, 2023):

Okay, you'll actually need the client for that. What do you mean by UdpStream?

<!-- gh-comment-id:1759536985 --> @djc commented on GitHub (Oct 12, 2023): Okay, you'll actually need the client for that. What do you mean by `UdpStream`?
Author
Owner

@qjmiao commented on GitHub (Oct 12, 2023):

Okay, you'll actually need the client for that. What do you mean by UdpStream?

For tcp, the below code is working,I‘d like to know how to replace tcp with udp

let addr = "127.0.0.1:53".parse().unwrap();
let (stream, sender) = TcpClientStream::<AsyncIoTokioAsStd<TokioTcpStream>>::new(addr);
let client = AsyncClient::new(stream, sender, None);

let (client, bg) = client.await.unwrap();
tokio::spawn(bg);
<!-- gh-comment-id:1759601772 --> @qjmiao commented on GitHub (Oct 12, 2023): > Okay, you'll actually need the client for that. What do you mean by `UdpStream`? For tcp, the below code is working,I‘d like to know how to replace tcp with udp let addr = "127.0.0.1:53".parse().unwrap(); let (stream, sender) = TcpClientStream::<AsyncIoTokioAsStd<TokioTcpStream>>::new(addr); let client = AsyncClient::new(stream, sender, None); let (client, bg) = client.await.unwrap(); tokio::spawn(bg);
Author
Owner

@bluejekyll commented on GitHub (Oct 12, 2023):

Have you looked at the documented examples, here? https://docs.rs/trust-dns-client/latest/trust_dns_client/#setup-a-connection

<!-- gh-comment-id:1759604816 --> @bluejekyll commented on GitHub (Oct 12, 2023): Have you looked at the documented examples, here? https://docs.rs/trust-dns-client/latest/trust_dns_client/#setup-a-connection
Author
Owner

@qjmiao commented on GitHub (Oct 12, 2023):

Have you looked at the documented examples, here? https://docs.rs/trust-dns-client/latest/trust_dns_client/#setup-a-connection

Yes,the AsyncClient example is for tcp stream only

<!-- gh-comment-id:1759629052 --> @qjmiao commented on GitHub (Oct 12, 2023): > Have you looked at the documented examples, here? https://docs.rs/trust-dns-client/latest/trust_dns_client/#setup-a-connection Yes,the AsyncClient example is for tcp stream only
Author
Owner

@bluejekyll commented on GitHub (Oct 12, 2023):

This is the same interface as the TCP variant, https://docs.rs/trust-dns-client/latest/trust_dns_client/udp/struct.UdpClientStream.html#method.new

it should work the same was as that tcp example in an async context.

<!-- gh-comment-id:1759638837 --> @bluejekyll commented on GitHub (Oct 12, 2023): This is the same interface as the TCP variant, https://docs.rs/trust-dns-client/latest/trust_dns_client/udp/struct.UdpClientStream.html#method.new it should work the same was as that tcp example in an async context.
Author
Owner

@qjmiao commented on GitHub (Oct 12, 2023):

This is the same interface as the TCP variant, https://docs.rs/trust-dns-client/latest/trust_dns_client/udp/struct.UdpClientStream.html#method.new

it should work the same was as that tcp example in an async context.

For UDP, how can I get sender: BufDnsStreamHandle for the second param of asyncclient::new()

pub fn UdpClientStream::new(name_server: SocketAddr) -> UdpClientConnect<S, NoopMessageFinalizer>

pub fn TcpClientStream::new(name_server: SocketAddr) -> (TcpClientConnect<S>, BufDnsStreamHandle)

pub async fn AsyncClient::new<F, S>(stream: F, stream_handle: BufDnsStreamHandle, signer: Option<Arc<Signer>>)

<!-- gh-comment-id:1759668119 --> @qjmiao commented on GitHub (Oct 12, 2023): > This is the same interface as the TCP variant, https://docs.rs/trust-dns-client/latest/trust_dns_client/udp/struct.UdpClientStream.html#method.new > > it should work the same was as that tcp example in an async context. ``` For UDP, how can I get sender: BufDnsStreamHandle for the second param of asyncclient::new() pub fn UdpClientStream::new(name_server: SocketAddr) -> UdpClientConnect<S, NoopMessageFinalizer> pub fn TcpClientStream::new(name_server: SocketAddr) -> (TcpClientConnect<S>, BufDnsStreamHandle) pub async fn AsyncClient::new<F, S>(stream: F, stream_handle: BufDnsStreamHandle, signer: Option<Arc<Signer>>) ```
Author
Owner

@bluejekyll commented on GitHub (Oct 12, 2023):

Ah, I'm sorry. We should add an example of this. I even gave you bad advice on the interface, here's a good example for you:

github.com/bluejekyll/trust-dns@c9cc5c9dd0/util/src/bin/dns.rs (L251-L253)

edit: for some additional context on why TCP and UDP have different interfaces, UDP can do more operations in the foreground thread because the Socket is shared for all operations. TCP on the other hand needs to establish a new socket and connection for each request, and that happens in a background task, which is why it has a slightly more complicated interface.

<!-- gh-comment-id:1759729810 --> @bluejekyll commented on GitHub (Oct 12, 2023): Ah, I'm sorry. We should add an example of this. I even gave you bad advice on the interface, here's a good example for you: https://github.com/bluejekyll/trust-dns/blob/c9cc5c9dd0e7a48fc5246b457b70f7bb5850d4be/util/src/bin/dns.rs#L251-L253 edit: for some additional context on why TCP and UDP have different interfaces, UDP can do more operations in the foreground thread because the Socket is shared for all operations. TCP on the other hand needs to establish a new socket and connection for each request, and that happens in a background task, which is why it has a slightly more complicated interface.
Author
Owner

@qjmiao commented on GitHub (Oct 12, 2023):

Ah, I'm sorry. We should add an example of this. I even gave you bad advice on the interface, here's a good example for you:

github.com/bluejekyll/trust-dns@c9cc5c9dd0/util/src/bin/dns.rs (L251-L253)

edit: for some additional context on why TCP and UDP have different interfaces, UDP can do more operations in the foreground thread because the Socket is shared for all operations. TCP on the other hand needs to establish a new socket and connection for each request, and that happens in a background task, which is why it has a slightly more complicated interface.

Thanks very much for your UDP example code. It's working for me now.
Great!

<!-- gh-comment-id:1760513248 --> @qjmiao commented on GitHub (Oct 12, 2023): > Ah, I'm sorry. We should add an example of this. I even gave you bad advice on the interface, here's a good example for you: > > https://github.com/bluejekyll/trust-dns/blob/c9cc5c9dd0e7a48fc5246b457b70f7bb5850d4be/util/src/bin/dns.rs#L251-L253 > > edit: for some additional context on why TCP and UDP have different interfaces, UDP can do more operations in the foreground thread because the Socket is shared for all operations. TCP on the other hand needs to establish a new socket and connection for each request, and that happens in a background task, which is why it has a slightly more complicated interface. Thanks very much for your UDP example code. It's working for me now. Great!
Author
Owner

@mdecimus commented on GitHub (Feb 15, 2024):

Hi,

I have a follow-up question, how can I use AsyncClient with a UdpStream and SigSigner? The following doesn't work because UdpClientStream requires the NoopMessageFinalizer:

    let signer = SigSigner::sig0(sig0key, key, Name::from_str("update.example.com.").unwrap());
    let address = "8.8.8.8:53".parse().unwrap();
    let conn = UdpClientStream::<UdpSocket>::with_timeout_and_signer(
        address,
        Duration::from_secs(5),
        Some(Arc::new(signer)),
    );

And the following doesn't work either as DnsClientStream is not implemented for UdpClientStream:

    let conn = UdpClientStream::<UdpSocket>::new(address);
    let (client, bg) = AsyncClient::new(conn, BufDnsStreamHandle::new(address), signer)
        .await
        .unwrap();

And one final slightly related question, do you have plans to support Sig0 RSA signing without requiring OpenSSL? I want to avoid this dependency and currently only ECDSA and ED25519 are available through ring when OpenSSL is disabled.

Edit: Just found out how to do it. In case someone is looking for an example on how to use SigSigner on an async UDP connection, here it is:

    let conn = UdpClientConnection::new(address)
        .unwrap()
        .new_stream(Some(Arc::new(Signer::from(signer))));
    let (client, bg) = AsyncClient::connect(conn).await.unwrap();
<!-- gh-comment-id:1945770697 --> @mdecimus commented on GitHub (Feb 15, 2024): Hi, I have a follow-up question, how can I use `AsyncClient` with a `UdpStream` and `SigSigner`? The following doesn't work because `UdpClientStream` requires the `NoopMessageFinalizer`: ```rust let signer = SigSigner::sig0(sig0key, key, Name::from_str("update.example.com.").unwrap()); let address = "8.8.8.8:53".parse().unwrap(); let conn = UdpClientStream::<UdpSocket>::with_timeout_and_signer( address, Duration::from_secs(5), Some(Arc::new(signer)), ); ``` And the following doesn't work either as `DnsClientStream` is not implemented for `UdpClientStream`: ```rust let conn = UdpClientStream::<UdpSocket>::new(address); let (client, bg) = AsyncClient::new(conn, BufDnsStreamHandle::new(address), signer) .await .unwrap(); ``` And one final slightly related question, do you have plans to support Sig0 RSA signing without requiring OpenSSL? I want to avoid this dependency and currently only ECDSA and ED25519 are available through `ring` when OpenSSL is disabled. **Edit**: Just found out how to do it. In case someone is looking for an example on how to use `SigSigner` on an async UDP connection, here it is: ```rust let conn = UdpClientConnection::new(address) .unwrap() .new_stream(Some(Arc::new(Signer::from(signer)))); let (client, bg) = AsyncClient::connect(conn).await.unwrap(); ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/hickory-dns#865
No description provided.