Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Network servers should not ignore ServiceError. #390

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

ximon18
Copy link
Member

@ximon18 ximon18 commented Sep 13, 2024

This PR addresses an omission in the net::server::dgram and net::server::stream modules whereby they iterate over the stream of service responses accepting only Some(Ok) results and cease iterating on anything else. To stop on None is fine, but to stop on Err without taking any action is not.

Background: The Service interface was designed such that services can easily return Err(ServiceError) with the inteion that this allows them to easily produce certain standard DNS error responses without doing the work of constructing the response message correclty, keeping their error handling code paths simple. The ServiceError type has an rcode() method which the network server was supposed to use to construct the appopriate DNS response message, e.g. ServiceError::InternalError translates to rcode SERVFAIL.

But since the network servers never handle the service error case other than to ignore it that means in such cases the client wouldn't receive any DNS response message at all! This was not the intention, it was simply overlooked and clearly there also aren't any test cases that exercise this.

This PR makes three improvements:

  1. Detect ServiceError and construct and return the appropriate DNS response error message to the client.
  2. Do this once in common code, factor out such common code from the network servers to a new ServiceInvoker base trait with default fn impls, with some network server specific methods to be filled in by the network server impls.
  3. Make the network server impls behave the same way for code that should already have been the same but through duplication had slight differences. E.g. till now the UDP server would spawn a background async task before even turning the message bytes into a Message object, while the TCP server would defer async task creation till a bit later.

This PR does NOT (yet?) address the lack of test cases for this logic.

…returning an appropriate DNS error message.

Factor common service invoking and response processing code out to new trait ServiceInvoker and implement the network server specific parts for the UDP and TCP servers.

Also simplifies some trait bounds.
@ximon18 ximon18 requested a review from a team September 13, 2024 12:08
@ximon18 ximon18 mentioned this pull request Sep 13, 2024
@ximon18 ximon18 added the bug Something isn't working label Sep 16, 2024
}
}
match Message::from_octets(buf) {
Err(err) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that in this case no error gets returned to the client

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a DNS request from which to extract a query ID to copy into the error response. So we could generate a FORMERR response and send it, but with what ID?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: When merged with main there is an additional Ok(msg) if msg.header().qr() => match stanza which also doesn't send a reply, but that DOES know the ID of the request and so should respond.

}
}
trace!("Finished processing service call results for request id {request_id}");
dispatcher.dispatch(request, service, ()).await
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the impression that if Message::from_octets fails the client doesn't get a reply

@@ -0,0 +1,188 @@
/// Common service invoking logic for network servers.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the check for QR be moved into this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't do that because I was trying to use as few server resources as possible and so immediately reject/discard incoming messages as soon as I can, where possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working unstable feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants