Skip to content

Commit c69e15c

Browse files
committed
[LLT-4202] Make lookup return error in case of failure on forward
Make the forward error visible instead of just filling the response buffer with an empty response.
1 parent 00a31c9 commit c69e15c

File tree

3 files changed

+75
-43
lines changed

3 files changed

+75
-43
lines changed

crates/server/src/authority/catalog.rs

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,15 @@ impl RequestHandler for Catalog {
139139
MessageType::Query => match request.op_code() {
140140
OpCode::Query => {
141141
debug!("query received: {}", request.id());
142-
let info = self.lookup(request, response_edns, response_handle).await;
142+
let info = self
143+
.lookup(request, response_edns, response_handle)
144+
.await
145+
.unwrap_or_else(|e| match e {
146+
LookupError::ResponseCode(code) => {
147+
ResponseInfo::response_code_error(request.header().id(), code)
148+
}
149+
_ => ResponseInfo::unknown(request.header().id()),
150+
});
143151

144152
Ok(info)
145153
}
@@ -346,7 +354,7 @@ impl Catalog {
346354
request: &Request,
347355
response_edns: Option<Edns>,
348356
response_handle: R,
349-
) -> ResponseInfo {
357+
) -> Result<ResponseInfo, LookupError> {
350358
let request_info = request.request_info();
351359
let authority = self.find(request_info.query.name());
352360

@@ -365,20 +373,18 @@ impl Catalog {
365373
// if this is empty then the there are no authorities registered that can handle the request
366374
let response = MessageResponseBuilder::new(Some(request.raw_query()));
367375

368-
let result = send_response(
376+
send_response(
369377
response_edns,
370378
response.error_msg(request.header(), ResponseCode::Refused),
371379
response_handle,
372380
)
373-
.await;
381+
.await
382+
.map_err(|e| {
383+
debug!("failed to send response: {}", e);
384+
LookupError::Io(e)
385+
})?;
374386

375-
match result {
376-
Err(e) => {
377-
debug!("failed to send response: {}", e);
378-
ResponseInfo::serve_failed()
379-
}
380-
Ok(r) => r,
381-
}
387+
Err(LookupError::ResponseCode(ResponseCode::Refused))
382388
}
383389
}
384390

@@ -405,7 +411,7 @@ async fn lookup<'a, R: ResponseHandler + Unpin>(
405411
request: &Request,
406412
response_edns: Option<Edns>,
407413
response_handle: R,
408-
) -> ResponseInfo {
414+
) -> Result<ResponseInfo, LookupError> {
409415
let query = request_info.query;
410416
debug!(
411417
"request: {} found authority: {}",
@@ -421,7 +427,7 @@ async fn lookup<'a, R: ResponseHandler + Unpin>(
421427
query,
422428
request.edns(),
423429
)
424-
.await;
430+
.await?;
425431

426432
let response = MessageResponseBuilder::new(Some(request.raw_query())).build(
427433
response_header,
@@ -431,15 +437,12 @@ async fn lookup<'a, R: ResponseHandler + Unpin>(
431437
sections.additionals.iter(),
432438
);
433439

434-
let result = send_response(response_edns.clone(), response, response_handle.clone()).await;
435-
436-
match result {
437-
Err(e) => {
438-
debug!("error sending response: {}", e);
439-
ResponseInfo::serve_failed()
440-
}
441-
Ok(i) => i,
442-
}
440+
send_response(response_edns.clone(), response, response_handle.clone())
441+
.await
442+
.map_err(|e| {
443+
debug!("failed to send response: {}", e);
444+
LookupError::Io(e)
445+
})
443446
}
444447

445448
#[allow(unused_variables)]
@@ -473,7 +476,7 @@ async fn build_response(
473476
request_header: &Header,
474477
query: &LowerQuery,
475478
edns: Option<&Edns>,
476-
) -> (Header, LookupSections) {
479+
) -> Result<(Header, LookupSections), LookupError> {
477480
let lookup_options = lookup_options_for_edns(edns);
478481

479482
// log algorithms being requested
@@ -501,14 +504,14 @@ async fn build_response(
501504
request_id,
502505
query,
503506
)
504-
.await
507+
.await?
505508
}
506509
ZoneType::Forward | ZoneType::Hint => {
507-
send_forwarded_response(future, request_header, &mut response_header).await
510+
send_forwarded_response(future, request_header, &mut response_header).await?
508511
}
509512
};
510513

511-
(response_header, sections)
514+
Ok((response_header, sections))
512515
}
513516

514517
async fn send_authoritative_response(
@@ -518,7 +521,7 @@ async fn send_authoritative_response(
518521
lookup_options: LookupOptions,
519522
request_id: u16,
520523
query: &LowerQuery,
521-
) -> LookupSections {
524+
) -> Result<LookupSections, LookupError> {
522525
// In this state we await the records, on success we transition to getting
523526
// NS records, which indicate an authoritative response.
524527
//
@@ -533,12 +536,12 @@ async fn send_authoritative_response(
533536
// TODO: there are probably other error cases that should just drop through (FormErr, ServFail)
534537
Err(LookupError::ResponseCode(ResponseCode::Refused)) => {
535538
response_header.set_response_code(ResponseCode::Refused);
536-
return LookupSections {
537-
answers: Box::new(AuthLookup::default()) as Box<dyn LookupObject>,
538-
ns: Box::new(AuthLookup::default()) as Box<dyn LookupObject>,
539-
soa: Box::new(AuthLookup::default()) as Box<dyn LookupObject>,
540-
additionals: Box::new(AuthLookup::default()) as Box<dyn LookupObject>,
541-
};
539+
return Ok(LookupSections {
540+
answers: Box::<AuthLookup>::default(),
541+
ns: Box::<AuthLookup>::default(),
542+
soa: Box::<AuthLookup>::default(),
543+
additionals: Box::<AuthLookup>::default(),
544+
});
542545
}
543546
Err(e) => {
544547
if e.is_nx_domain() {
@@ -607,19 +610,19 @@ async fn send_authoritative_response(
607610
),
608611
};
609612

610-
LookupSections {
613+
Ok(LookupSections {
611614
answers,
612615
ns: ns.unwrap_or_else(|| Box::new(AuthLookup::default()) as Box<dyn LookupObject>),
613616
soa: soa.unwrap_or_else(|| Box::new(AuthLookup::default()) as Box<dyn LookupObject>),
614617
additionals,
615-
}
618+
})
616619
}
617620

618621
async fn send_forwarded_response(
619622
future: impl Future<Output = Result<Box<dyn LookupObject>, LookupError>>,
620623
request_header: &Header,
621624
response_header: &mut Header,
622-
) -> LookupSections {
625+
) -> Result<LookupSections, LookupError> {
623626
response_header.set_recursion_available(true);
624627
response_header.set_authoritative(false);
625628

@@ -634,26 +637,31 @@ async fn send_forwarded_response(
634637
request_header.id()
635638
);
636639

637-
Box::new(EmptyLookup)
640+
return Err(LookupError::ResponseCode(ResponseCode::Refused));
638641
} else {
639642
match future.await {
640643
Err(e) => {
644+
debug!("error resolving: {}", e);
645+
if e.is_io() || e.is_unknown() {
646+
return Err(e);
647+
}
648+
649+
// If the server responds with NXDomain we want to copy this behavior
641650
if e.is_nx_domain() {
642651
response_header.set_response_code(ResponseCode::NXDomain);
643652
}
644-
debug!("error resolving: {}", e);
645653
Box::new(EmptyLookup)
646654
}
647655
Ok(rsp) => rsp,
648656
}
649657
};
650658

651-
LookupSections {
659+
Ok(LookupSections {
652660
answers,
653-
ns: Box::new(AuthLookup::default()) as Box<dyn LookupObject>,
654-
soa: Box::new(AuthLookup::default()) as Box<dyn LookupObject>,
655-
additionals: Box::new(AuthLookup::default()) as Box<dyn LookupObject>,
656-
}
661+
ns: Box::<AuthLookup>::default(),
662+
soa: Box::<AuthLookup>::default(),
663+
additionals: Box::<AuthLookup>::default(),
664+
})
657665
}
658666

659667
struct LookupSections {

crates/server/src/authority/error.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ impl LookupError {
5656
pub fn is_refused(&self) -> bool {
5757
matches!(*self, Self::ResponseCode(ResponseCode::Refused))
5858
}
59+
60+
/// This is an Io error
61+
pub fn is_io(&self) -> bool {
62+
matches!(*self, Self::Io(_))
63+
}
64+
65+
/// This is an unknown error
66+
pub fn is_unknown(&self) -> bool {
67+
matches!(*self, Self::ResponseCode(ResponseCode::Unknown(_)))
68+
}
5969
}
6070

6171
impl From<ResponseCode> for LookupError {

crates/server/src/server/request_handler.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,20 @@ impl ResponseInfo {
118118
header.set_response_code(ResponseCode::ServFail);
119119
header.into()
120120
}
121+
122+
pub(crate) fn response_code_error(id: u16, code: ResponseCode) -> Self {
123+
let mut header = Header::new();
124+
header.set_id(id);
125+
header.set_response_code(code);
126+
header.into()
127+
}
128+
129+
pub(crate) fn unknown(id: u16) -> Self {
130+
let mut header = Header::new();
131+
header.set_id(id);
132+
header.set_response_code(ResponseCode::Unknown(0));
133+
header.into()
134+
}
121135
}
122136

123137
impl From<Header> for ResponseInfo {

0 commit comments

Comments
 (0)