2014-07-16 00:26:02 +02:00
|
|
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2014 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
2014-07-18 13:59:49 +02:00
|
|
|
#include "in-addr-util.h"
|
|
|
|
|
2014-07-16 00:26:02 +02:00
|
|
|
typedef struct DnsServer DnsServer;
|
|
|
|
|
2014-08-01 16:04:12 +02:00
|
|
|
typedef enum DnsServerType {
|
|
|
|
DNS_SERVER_SYSTEM,
|
|
|
|
DNS_SERVER_FALLBACK,
|
|
|
|
DNS_SERVER_LINK,
|
|
|
|
} DnsServerType;
|
|
|
|
|
resolved: fallback to TCP if UDP fails
This is inspired by the logic in BIND [0], follow-up patches
will implement the reset of that scheme.
If we get a server error back, or if after several attempts we don't
get a reply at all, we switch from UDP to TCP for the given
server for the current and all subsequent requests. However, if
we ever successfully received a reply over UDP, we never fall
back to TCP, and once a grace-period has passed, we try to upgrade
again to using UDP. The grace-period starts off at five minutes
after the current feature level was verified and then grows
exponentially to six hours. This is to mitigate problems due
to temporary lack of network connectivity, but at the same time
avoid flooding the network with retries when the feature attempted
feature level genuinely does not work.
Note that UDP is likely much more commonly supported than TCP,
but depending on the path between the client and the server, we
may have more luck with TCP in case something is wrong. We really
do prefer UDP though, as that is much more lightweight, that is
why TCP is only the last resort.
[0]: <https://kb.isc.org/article/AA-01219/0/Refinements-to-EDNS-fallback-behavior-can-cause-different-outcomes-in-Recursive-Servers.html>
2015-07-06 08:15:25 +02:00
|
|
|
typedef enum DnsServerFeatureLevel {
|
|
|
|
DNS_SERVER_FEATURE_LEVEL_TCP,
|
|
|
|
DNS_SERVER_FEATURE_LEVEL_UDP,
|
2015-06-23 23:06:09 +02:00
|
|
|
DNS_SERVER_FEATURE_LEVEL_EDNS0,
|
2015-06-24 15:08:40 +02:00
|
|
|
DNS_SERVER_FEATURE_LEVEL_DO,
|
resolved: announce support for large UDP packets
This is often needed for proper DNSSEC support, and even to handle AAAA records
without falling back to TCP.
If the path between the client and server is fully compliant, this should always
work, however, that is not the case, and overlarge packets will get mysteriously
lost in some cases.
For that reason, we use a similar fallback mechanism as we do for palin EDNS0,
EDNS0+DO, etc.:
The large UDP size feature is different from the other supported feature, as we
cannot simply verify that it works based on receiving a reply (as the server
will usually send us much smaller packets than what we claim to support, so
simply receiving a reply does not mean much).
For that reason, we keep track of the largest UDP packet we ever received, as this
is the smallest known good size (defaulting to the standard 512 bytes). If
announcing the default large size of 4096 fails (in the same way as the other
features), we fall back to the known good size. The same logic of retrying after a
grace-period applies.
2015-07-06 16:48:24 +02:00
|
|
|
DNS_SERVER_FEATURE_LEVEL_LARGE,
|
resolved: fallback to TCP if UDP fails
This is inspired by the logic in BIND [0], follow-up patches
will implement the reset of that scheme.
If we get a server error back, or if after several attempts we don't
get a reply at all, we switch from UDP to TCP for the given
server for the current and all subsequent requests. However, if
we ever successfully received a reply over UDP, we never fall
back to TCP, and once a grace-period has passed, we try to upgrade
again to using UDP. The grace-period starts off at five minutes
after the current feature level was verified and then grows
exponentially to six hours. This is to mitigate problems due
to temporary lack of network connectivity, but at the same time
avoid flooding the network with retries when the feature attempted
feature level genuinely does not work.
Note that UDP is likely much more commonly supported than TCP,
but depending on the path between the client and the server, we
may have more luck with TCP in case something is wrong. We really
do prefer UDP though, as that is much more lightweight, that is
why TCP is only the last resort.
[0]: <https://kb.isc.org/article/AA-01219/0/Refinements-to-EDNS-fallback-behavior-can-cause-different-outcomes-in-Recursive-Servers.html>
2015-07-06 08:15:25 +02:00
|
|
|
_DNS_SERVER_FEATURE_LEVEL_MAX,
|
|
|
|
_DNS_SERVER_FEATURE_LEVEL_INVALID = -1
|
|
|
|
} DnsServerFeatureLevel;
|
|
|
|
|
|
|
|
#define DNS_SERVER_FEATURE_LEVEL_WORST 0
|
|
|
|
#define DNS_SERVER_FEATURE_LEVEL_BEST (_DNS_SERVER_FEATURE_LEVEL_MAX - 1)
|
|
|
|
|
|
|
|
const char* dns_server_feature_level_to_string(int i) _const_;
|
|
|
|
int dns_server_feature_level_from_string(const char *s) _pure_;
|
|
|
|
|
2014-08-12 19:32:55 +02:00
|
|
|
#include "resolved-link.h"
|
resolved: fallback to TCP if UDP fails
This is inspired by the logic in BIND [0], follow-up patches
will implement the reset of that scheme.
If we get a server error back, or if after several attempts we don't
get a reply at all, we switch from UDP to TCP for the given
server for the current and all subsequent requests. However, if
we ever successfully received a reply over UDP, we never fall
back to TCP, and once a grace-period has passed, we try to upgrade
again to using UDP. The grace-period starts off at five minutes
after the current feature level was verified and then grows
exponentially to six hours. This is to mitigate problems due
to temporary lack of network connectivity, but at the same time
avoid flooding the network with retries when the feature attempted
feature level genuinely does not work.
Note that UDP is likely much more commonly supported than TCP,
but depending on the path between the client and the server, we
may have more luck with TCP in case something is wrong. We really
do prefer UDP though, as that is much more lightweight, that is
why TCP is only the last resort.
[0]: <https://kb.isc.org/article/AA-01219/0/Refinements-to-EDNS-fallback-behavior-can-cause-different-outcomes-in-Recursive-Servers.html>
2015-07-06 08:15:25 +02:00
|
|
|
#include "resolved-manager.h"
|
2014-08-12 19:32:55 +02:00
|
|
|
|
2014-07-16 00:26:02 +02:00
|
|
|
struct DnsServer {
|
|
|
|
Manager *manager;
|
|
|
|
|
2015-06-24 18:41:46 +02:00
|
|
|
unsigned n_ref;
|
|
|
|
|
2014-08-01 16:04:12 +02:00
|
|
|
DnsServerType type;
|
2014-07-18 13:59:49 +02:00
|
|
|
Link *link;
|
|
|
|
|
2014-07-18 16:09:30 +02:00
|
|
|
int family;
|
2014-07-16 00:26:02 +02:00
|
|
|
union in_addr_union address;
|
|
|
|
|
2015-07-28 02:32:24 +02:00
|
|
|
usec_t resend_timeout;
|
|
|
|
usec_t max_rtt;
|
|
|
|
|
resolved: fallback to TCP if UDP fails
This is inspired by the logic in BIND [0], follow-up patches
will implement the reset of that scheme.
If we get a server error back, or if after several attempts we don't
get a reply at all, we switch from UDP to TCP for the given
server for the current and all subsequent requests. However, if
we ever successfully received a reply over UDP, we never fall
back to TCP, and once a grace-period has passed, we try to upgrade
again to using UDP. The grace-period starts off at five minutes
after the current feature level was verified and then grows
exponentially to six hours. This is to mitigate problems due
to temporary lack of network connectivity, but at the same time
avoid flooding the network with retries when the feature attempted
feature level genuinely does not work.
Note that UDP is likely much more commonly supported than TCP,
but depending on the path between the client and the server, we
may have more luck with TCP in case something is wrong. We really
do prefer UDP though, as that is much more lightweight, that is
why TCP is only the last resort.
[0]: <https://kb.isc.org/article/AA-01219/0/Refinements-to-EDNS-fallback-behavior-can-cause-different-outcomes-in-Recursive-Servers.html>
2015-07-06 08:15:25 +02:00
|
|
|
DnsServerFeatureLevel verified_features;
|
|
|
|
DnsServerFeatureLevel possible_features;
|
resolved: announce support for large UDP packets
This is often needed for proper DNSSEC support, and even to handle AAAA records
without falling back to TCP.
If the path between the client and server is fully compliant, this should always
work, however, that is not the case, and overlarge packets will get mysteriously
lost in some cases.
For that reason, we use a similar fallback mechanism as we do for palin EDNS0,
EDNS0+DO, etc.:
The large UDP size feature is different from the other supported feature, as we
cannot simply verify that it works based on receiving a reply (as the server
will usually send us much smaller packets than what we claim to support, so
simply receiving a reply does not mean much).
For that reason, we keep track of the largest UDP packet we ever received, as this
is the smallest known good size (defaulting to the standard 512 bytes). If
announcing the default large size of 4096 fails (in the same way as the other
features), we fall back to the known good size. The same logic of retrying after a
grace-period applies.
2015-07-06 16:48:24 +02:00
|
|
|
size_t received_udp_packet_max;
|
resolved: fallback to TCP if UDP fails
This is inspired by the logic in BIND [0], follow-up patches
will implement the reset of that scheme.
If we get a server error back, or if after several attempts we don't
get a reply at all, we switch from UDP to TCP for the given
server for the current and all subsequent requests. However, if
we ever successfully received a reply over UDP, we never fall
back to TCP, and once a grace-period has passed, we try to upgrade
again to using UDP. The grace-period starts off at five minutes
after the current feature level was verified and then grows
exponentially to six hours. This is to mitigate problems due
to temporary lack of network connectivity, but at the same time
avoid flooding the network with retries when the feature attempted
feature level genuinely does not work.
Note that UDP is likely much more commonly supported than TCP,
but depending on the path between the client and the server, we
may have more luck with TCP in case something is wrong. We really
do prefer UDP though, as that is much more lightweight, that is
why TCP is only the last resort.
[0]: <https://kb.isc.org/article/AA-01219/0/Refinements-to-EDNS-fallback-behavior-can-cause-different-outcomes-in-Recursive-Servers.html>
2015-07-06 08:15:25 +02:00
|
|
|
unsigned n_failed_attempts;
|
|
|
|
usec_t verified_usec;
|
|
|
|
usec_t features_grace_period_usec;
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-12-25 15:05:46 +01:00
|
|
|
/* Indicates whether responses are augmented with RRSIG by
|
|
|
|
* server or not. Note that this is orthogonal to the feature
|
|
|
|
* level stuff, as it's only information describing responses,
|
|
|
|
* and has no effect on how the questions are asked. */
|
|
|
|
bool rrsig_missing:1;
|
|
|
|
|
|
|
|
/* Used when GC'ing old DNS servers when configuration changes. */
|
|
|
|
bool marked:1;
|
|
|
|
|
2015-11-24 17:59:40 +01:00
|
|
|
/* If linked is set, then this server appears in the servers linked list */
|
|
|
|
bool linked:1;
|
2014-07-16 00:26:02 +02:00
|
|
|
LIST_FIELDS(DnsServer, servers);
|
|
|
|
};
|
|
|
|
|
|
|
|
int dns_server_new(
|
|
|
|
Manager *m,
|
2015-11-24 20:50:37 +01:00
|
|
|
DnsServer **ret,
|
2014-08-01 16:04:12 +02:00
|
|
|
DnsServerType type,
|
2015-11-24 20:50:37 +01:00
|
|
|
Link *link,
|
2014-07-18 16:09:30 +02:00
|
|
|
int family,
|
2014-07-18 13:59:49 +02:00
|
|
|
const union in_addr_union *address);
|
2014-07-16 00:26:02 +02:00
|
|
|
|
2015-06-24 18:41:46 +02:00
|
|
|
DnsServer* dns_server_ref(DnsServer *s);
|
|
|
|
DnsServer* dns_server_unref(DnsServer *s);
|
2014-08-12 12:21:10 +02:00
|
|
|
|
2015-11-24 17:59:40 +01:00
|
|
|
void dns_server_unlink(DnsServer *s);
|
2015-11-24 20:50:37 +01:00
|
|
|
void dns_server_move_back_and_unmark(DnsServer *s);
|
2015-11-24 17:59:40 +01:00
|
|
|
|
resolved: announce support for large UDP packets
This is often needed for proper DNSSEC support, and even to handle AAAA records
without falling back to TCP.
If the path between the client and server is fully compliant, this should always
work, however, that is not the case, and overlarge packets will get mysteriously
lost in some cases.
For that reason, we use a similar fallback mechanism as we do for palin EDNS0,
EDNS0+DO, etc.:
The large UDP size feature is different from the other supported feature, as we
cannot simply verify that it works based on receiving a reply (as the server
will usually send us much smaller packets than what we claim to support, so
simply receiving a reply does not mean much).
For that reason, we keep track of the largest UDP packet we ever received, as this
is the smallest known good size (defaulting to the standard 512 bytes). If
announcing the default large size of 4096 fails (in the same way as the other
features), we fall back to the known good size. The same logic of retrying after a
grace-period applies.
2015-07-06 16:48:24 +02:00
|
|
|
void dns_server_packet_received(DnsServer *s, DnsServerFeatureLevel features, usec_t rtt, size_t size);
|
resolved: fallback to TCP if UDP fails
This is inspired by the logic in BIND [0], follow-up patches
will implement the reset of that scheme.
If we get a server error back, or if after several attempts we don't
get a reply at all, we switch from UDP to TCP for the given
server for the current and all subsequent requests. However, if
we ever successfully received a reply over UDP, we never fall
back to TCP, and once a grace-period has passed, we try to upgrade
again to using UDP. The grace-period starts off at five minutes
after the current feature level was verified and then grows
exponentially to six hours. This is to mitigate problems due
to temporary lack of network connectivity, but at the same time
avoid flooding the network with retries when the feature attempted
feature level genuinely does not work.
Note that UDP is likely much more commonly supported than TCP,
but depending on the path between the client and the server, we
may have more luck with TCP in case something is wrong. We really
do prefer UDP though, as that is much more lightweight, that is
why TCP is only the last resort.
[0]: <https://kb.isc.org/article/AA-01219/0/Refinements-to-EDNS-fallback-behavior-can-cause-different-outcomes-in-Recursive-Servers.html>
2015-07-06 08:15:25 +02:00
|
|
|
void dns_server_packet_lost(DnsServer *s, DnsServerFeatureLevel features, usec_t usec);
|
2015-07-16 14:39:55 +02:00
|
|
|
void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel features);
|
2015-12-25 15:05:46 +01:00
|
|
|
void dns_server_packet_rrsig_missing(DnsServer *s);
|
2015-07-28 02:32:24 +02:00
|
|
|
|
2015-11-24 21:27:29 +01:00
|
|
|
DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr);
|
|
|
|
|
|
|
|
void dns_server_unlink_all(DnsServer *first);
|
|
|
|
void dns_server_unlink_marked(DnsServer *first);
|
|
|
|
void dns_server_mark_all(DnsServer *first);
|
2015-11-24 17:03:12 +01:00
|
|
|
|
2015-11-24 21:27:29 +01:00
|
|
|
DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t);
|
2015-11-24 16:48:13 +01:00
|
|
|
|
2015-11-24 17:59:40 +01:00
|
|
|
DnsServer *manager_set_dns_server(Manager *m, DnsServer *s);
|
|
|
|
DnsServer *manager_get_dns_server(Manager *m);
|
|
|
|
void manager_next_dns_server(Manager *m);
|
|
|
|
|
2015-06-24 18:54:12 +02:00
|
|
|
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
|
|
|
|
|
resolved: fallback to TCP if UDP fails
This is inspired by the logic in BIND [0], follow-up patches
will implement the reset of that scheme.
If we get a server error back, or if after several attempts we don't
get a reply at all, we switch from UDP to TCP for the given
server for the current and all subsequent requests. However, if
we ever successfully received a reply over UDP, we never fall
back to TCP, and once a grace-period has passed, we try to upgrade
again to using UDP. The grace-period starts off at five minutes
after the current feature level was verified and then grows
exponentially to six hours. This is to mitigate problems due
to temporary lack of network connectivity, but at the same time
avoid flooding the network with retries when the feature attempted
feature level genuinely does not work.
Note that UDP is likely much more commonly supported than TCP,
but depending on the path between the client and the server, we
may have more luck with TCP in case something is wrong. We really
do prefer UDP though, as that is much more lightweight, that is
why TCP is only the last resort.
[0]: <https://kb.isc.org/article/AA-01219/0/Refinements-to-EDNS-fallback-behavior-can-cause-different-outcomes-in-Recursive-Servers.html>
2015-07-06 08:15:25 +02:00
|
|
|
DnsServerFeatureLevel dns_server_possible_features(DnsServer *s);
|
|
|
|
|
2014-08-13 01:00:18 +02:00
|
|
|
extern const struct hash_ops dns_server_hash_ops;
|