--------
add-cookies-unsupported *IP* [*IP*...]
Add non-expiring IPs of servers that do not support cookies to the cookie table.
+ Optionally *IP:port* can be specified, the default is to use port 53.
+ The listed addresses will be placed as ``Unsupported`` in the cookie support table and will not be pruned.
add-dont-throttle-names *NAME* [*NAME*...]
Add names for nameserver domains that may not be throttled.
clear-cookies [*IP*...]
Remove entries from cookie table. If *IP* is ``*``, remove all.
+ Optionally *IP:port* can be specified, the default is to use port 53.
clear-dont-throttle-names *NAME* [*NAME*...]
Remove names that are not allowed to be throttled. If *NAME* is ``*``, remove all
^^^^^^^^^^^^
- The :ref:`setting-yaml-outgoing.cookies` setting has been introduced to implement cookie support for contacting authoritative servers and forwarders. See :rfc:`7873` and :rfc:`9018`.
-- The :ref:`setting-yaml-outgoing.cookies_unsupported` setting has been introduced to to permanently mark authoritative servers as not supporting cookies.
+- The :ref:`setting-yaml-outgoing.cookies_unsupported` setting has been introduced to permanently mark authoritative servers as not supporting cookies.
:program:`rec_control`
^^^^^^^^^^^^^^^^^^^^^^
static bool g_cookies = false;
-void enableOutgoingCookies(bool flag, const string& unsupported)
+std::string enableOutgoingCookies(bool flag, const string& unsupported)
{
g_cookies = flag;
if (g_cookies) {
std::vector<std::string> parts;
stringtok(parts, unsupported, ", ");
- addCookiesUnsupported(parts.begin(), parts.end());
+ std::string errors;
+ addCookiesUnsupported(parts.begin(), parts.end(), errors);
+ return errors;
}
+ return {};
}
thread_local TCPOutConnectionManager t_tcp_manager;
static LockGuarded<CookieStore> s_cookiestore;
-uint64_t addCookiesUnsupported(vector<string>::iterator begin, vector<string>::iterator end)
+uint64_t addCookiesUnsupported(vector<string>::iterator begin, vector<string>::iterator end, string& errors)
{
auto lock = s_cookiestore.lock();
uint64_t count = 0;
}
++count;
}
- catch (const PDNSException&) {
- ;
+ catch (const PDNSException& error) {
+ if (!errors.empty()) {
+ errors += ", ";
+ }
+ errors += error.reason;
}
++begin;
}
return count;
}
-uint64_t clearCookies(vector<string>::iterator begin, vector<string>::iterator end)
+uint64_t clearCookies(vector<string>::iterator begin, vector<string>::iterator end, string& errors)
{
auto lock = s_cookiestore.lock();
uint64_t count = 0;
try {
count += lock->erase(ComboAddress(*begin, 53));
}
- catch (const PDNSException&) {
- ;
+ catch (const PDNSException& error) {
+ if (!errors.empty()) {
+ errors += ", ";
+ }
+ errors += error.reason;
}
++begin;
}
cookieSentOut = found->d_cookie;
addressToBindTo = found->d_localaddress;
opts.emplace_back(EDNSOptionCode::COOKIE, cookieSentOut->makeOptString());
- found->d_lastupdate = now.tv_sec;
+ found->d_lastused = now.tv_sec;
VLOG(log, "Sending stored cookie info to " << address.toString() << ": " << found->d_cookie.toDisplayString() << endl);
break;
case CookieEntry::Support::Unsupported:
LWResult::Result asyncresolve(const OptLog& log, const ComboAddress& address, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, const ResolveContext& context, const std::shared_ptr<std::vector<std::unique_ptr<RemoteLogger>>>& outgoingLoggers, const std::shared_ptr<std::vector<std::unique_ptr<FrameStreamLogger>>>& fstrmLoggers, const std::set<uint16_t>& exportTypes, LWResult* lwr, bool* chained);
uint64_t dumpCookies(int fileDesc);
-uint64_t clearCookies(vector<string>::iterator begin, vector<string>::iterator end);
-uint64_t addCookiesUnsupported(vector<string>::iterator begin, vector<string>::iterator end);
+uint64_t clearCookies(vector<string>::iterator begin, vector<string>::iterator end, string& errors);
+uint64_t addCookiesUnsupported(vector<string>::iterator begin, vector<string>::iterator end, string& errors);
void pruneCookies(time_t cutoff);
-void enableOutgoingCookies(bool flag, const std::string& unsupported);
+std::string enableOutgoingCookies(bool flag, const std::string& unsupported);
entry.d_address.toStringWithPortExcept(53).c_str(), entry.d_localaddress.toString().c_str(),
entry.d_cookie.toDisplayString().c_str(),
CookieEntry::toString(entry.d_support).c_str(),
- entry.d_lastupdate == std::numeric_limits<time_t>::max() ? "Forever" : timestamp(entry.d_lastupdate, tmp));
+ entry.d_lastused == std::numeric_limits<time_t>::max() ? "Forever" : timestamp(entry.d_lastused, tmp));
}
return count;
}
CookieStore is used to keep track of client cookies used for contacting authoritative servers.
According to RFC 7873 and RFC 9018, it has the following design.
- - Cookies are stored with an auth IP address as primary index and are generated randomly.
+ - Cookies are stored with an auth IP:port address as primary index and are generated randomly.
- If an auth does not support cookies, it is marked as such and no cookies will be sent to it
for a period of time. When a cookie is sent again, it must be a newly generated one.
void setSupport(Support support, time_t now) const // modifying mutable field
{
- d_lastupdate = now;
+ d_lastused = now;
d_support = support;
}
ComboAddress d_address;
mutable ComboAddress d_localaddress; // The address we were bound to, see RFC 9018
mutable EDNSCookiesOpt d_cookie; // Contains both client and server cookie
- mutable time_t d_lastupdate{};
+ mutable time_t d_lastused{};
mutable Support d_support{Support::Unsupported};
};
class CookieStore : public multi_index_container<CookieEntry,
indexed_by<ordered_unique<tag<ComboAddress>, member<CookieEntry, ComboAddress, &CookieEntry::d_address>>,
- ordered_non_unique<tag<time_t>, member<CookieEntry, time_t, &CookieEntry::d_lastupdate>>>>
+ ordered_non_unique<tag<time_t>, member<CookieEntry, time_t, &CookieEntry::d_lastused>>>>
{
public:
void prune(time_t cutoff);
g_paddingOutgoing = ::arg().mustDo("edns-padding-out");
g_ECSHardening = ::arg().mustDo("edns-subnet-harden");
+ // Ignong errors return value, as YAML parsing already checked the format of the entries.
enableOutgoingCookies(::arg().mustDo("outgoing-cookies"), ::arg()["outgoing-cookies-unsupported"]);
RecThreadInfo::setNumDistributorThreads(::arg().asNum("distributor-threads"));
'name' : 'cookies_unsupported',
'section' : 'outgoing',
'oldname': 'outgoing-cookies-unsupported',
- 'type': LType.ListStrings,
+ 'type': LType.ListSocketAddresses,
'default': '',
- 'help': 'Addresses of authoritative servers that do not support cookies',
+ 'help': 'Addresses (with optional port) of authoritative servers that do not support cookies',
'doc': '''
-Addresses of servers that do not properly support DNS cookies (:rfc:`7873`, :rfc:`9018`). Recursor wil not even try to probe these servers for cookie support.
+Addresses of servers that do not properly support DNS cookies (:rfc:`7873`, :rfc:`9018`). Recursor wil not even try to probe these servers for cookie support. If no port is specified port 53 is used.
''',
'versionadded': '5.3.0',
},
return doDumpCache(socket, begin, end);
}
if (cmd == "clear-cookies") {
- auto count = clearCookies(begin, end);
- return {0, "Cleared " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " from cookies table\n"};
+ string errors;
+ auto count = clearCookies(begin, end, errors);
+ if (errors.empty()) {
+ return {0, "Cleared " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " from cookies table\n"};
+ }
+ return {1, "Cleared " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " from cookies table, errors: " + errors + "\n"};
}
if (cmd == "add-cookies-unsupported") {
- auto count = addCookiesUnsupported(begin, end);
- return {0, "Added " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " to cookies table\n"};
+ string errors;
+ auto count = addCookiesUnsupported(begin, end, errors);
+ if (errors.empty()) {
+ return {0, "Added " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " to cookies table\n"};
+ }
+ return {1, "Added " + std::to_string(count) + " entr" + addS(count, "y", "ies") + " to cookies table, errors: " + errors + "\n"};
}
if (cmd == "dump-cookies") {
return doDumpToFile(socket, pleaseDumpCookiesMap, cmd, false);
tcp2 = self.recControl(confdir, 'get tcp-outqueries')
self.assertEqual(tcp1, tcp2)
- # Case: we get a an correct client and server cookie back
+ # Case: we get a correct client and server cookie back
# We do not clear the cookie tables, so the old server cookie gets re-used
query = dns.message.make_query('supported2.cookies.example.', 'A')
expected = dns.rrset.from_text('supported2.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
confdir = os.path.join('configs', self._confdir)
# Case: rec gets a BADCOOKIE, even on retry and should fall back to TCP
self.recControl(confdir, 'clear-cookies', '*')
+ tcp1 = self.recControl(confdir, 'get tcp-outqueries')
query = dns.message.make_query('badcookie.cookies.example.', 'A')
expected = dns.rrset.from_text('badcookie.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')
res = self.sendUDPQuery(query)
self.assertRcodeEqual(res, dns.rcode.NOERROR)
self.assertRRsetInAnswer(res, expected)
self.checkCookies('Supported')
+ tcp2 = int(self.recControl(confdir, 'get tcp-outqueries'))
+ self.assertEqual(int(tcp1) + 1, int(tcp2))
def testAuthSendsMalformedCookie(self):
confdir = os.path.join('configs', self._confdir)
self.assertRRsetInAnswer(res, expected)
self.checkCookies('Supported')
- # Case: we get a an correct client and server cookie back
- # We HAVE cleared the cookie tables, so the old server cookie is fogotten
+ # Case: we get a correct client and server cookie back
+ # We HAVE cleared the cookie tables, so the old server cookie is forgotten
self.recControl(confdir, 'clear-cookies', '*')
query = dns.message.make_query('supported4.cookies.example.', 'A')
expected = dns.rrset.from_text('supported4.cookies.example.', 15, dns.rdataclass.IN, 'A', '127.0.0.1')