From 4c03e69ab845f703c1ffa3b7772938ca98cce44d Mon Sep 17 00:00:00 2001 From: Andreas Gustafsson Date: Mon, 19 Mar 2001 20:52:21 +0000 Subject: [PATCH] 781. [func] Avoid error packet loops by dropping duplicate FORMERR responses. [RT #1006] --- CHANGES | 4 ++++ bin/named/client.c | 36 +++++++++++++++++++++++++++++++- bin/named/include/named/client.h | 13 +++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index b2d882c67f..052accc16f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ + + 781. [func] Avoid error packet loops by dropping duplicate FORMERR + responses. [RT #1006] + 780. [bug] Error handling code dealing with out of memory or other rare errors could lead to assertion failures when calling functions on unitialized names. [RT #1065] diff --git a/bin/named/client.c b/bin/named/client.c index 3b42ff463c..943e55808b 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.c,v 1.159 2001/03/12 22:27:14 bwelling Exp $ */ +/* $Id: client.c,v 1.160 2001/03/19 20:52:19 gson Exp $ */ #include @@ -950,6 +950,33 @@ ns_client_error(ns_client_t *client, isc_result_t result) { } } message->rcode = rcode; + + /* + * FORMERR loop avoidance: If we sent a FORMERR message + * with the same ID to the same client less than two + * seconds ago, assume that we are in an infinite error + * packet dialog with a server for some protocol whose + * error responses look enough like DNS queries to + * elicit a FORMERR response. Drop a packet to break + * the loop. + */ + if (rcode == dns_rcode_formerr) { + if (isc_sockaddr_equal(&client->peeraddr, + &client->formerrcache.addr) && + message->id == client->formerrcache.id && + client->requesttime - client->formerrcache.time < 2) { + /* Drop packet. */ + ns_client_log(client, NS_LOGCATEGORY_CLIENT, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1), + "possible error packet loop, " + "FORMERR dropped"); + ns_client_next(client, result); + return; + } + client->formerrcache.addr = client->peeraddr; + client->formerrcache.time = client->requesttime; + client->formerrcache.id = message->id; + } ns_client_send(client); } @@ -1618,6 +1645,13 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL, NS_EVENT_CLIENTCONTROL, client_start, client, client, NULL, NULL); + /* + * Initialize FORMERR cache to sentinel value that will not match + * any actual FORMERR response. + */ + isc_sockaddr_any(&client->formerrcache.addr); + client->formerrcache.time = 0; + client->formerrcache.id = 0; ISC_LINK_INIT(client, link); client->list = NULL; diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h index b86c5ce36c..5baf92ba5a 100644 --- a/bin/named/include/named/client.h +++ b/bin/named/include/named/client.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: client.h,v 1.56 2001/03/11 06:19:39 marka Exp $ */ +/* $Id: client.h,v 1.57 2001/03/19 20:52:21 gson Exp $ */ #ifndef NAMED_CLIENT_H #define NAMED_CLIENT_H 1 @@ -133,6 +133,17 @@ struct ns_client { isc_boolean_t peeraddr_valid; struct in6_pktinfo pktinfo; isc_event_t ctlevent; + /* + * Information about recent FORMERR response(s), for + * FORMERR loop avoidance. This is separate for each + * client object rather than global only to avoid + * the need for locking. + */ + struct { + isc_sockaddr_t addr; + isc_stdtime_t time; + dns_messageid_t id; + } formerrcache; ISC_LINK(ns_client_t) link; /* * The list 'link' is part of, or NULL if not on any list.