mirror of
https://github.com/systemd/systemd.git
synced 2024-10-31 16:21:26 +03:00
resolved: disable path MTU discovery for UDP traffic
This disables path MTU discovery both for our UDP upstream connections and our UDP stub, following the suggestions of: https://blog.apnic.net/2019/07/12/its-time-to-consider-avoiding-ip-fragmentation-in-the-dns/ This more or less follows the model of other DNS servers on this.
This commit is contained in:
parent
95aa3937da
commit
eb170e75ab
@ -410,6 +410,11 @@ static int dns_scope_socket(
|
|||||||
r = socket_set_recvpktinfo(fd, sa.sa.sa_family, true);
|
r = socket_set_recvpktinfo(fd, sa.sa.sa_family, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
/* Turn of path MTU discovery for security reasons */
|
||||||
|
r = socket_disable_pmtud(fd, sa.sa.sa_family);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to disable UDP PMTUD, ignoring: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret_socket_address)
|
if (ret_socket_address)
|
||||||
|
@ -1117,6 +1117,12 @@ static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int ty
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (type == SOCK_DGRAM) {
|
||||||
|
r = socket_disable_pmtud(fd, l->family);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to disable UDP PMTUD, ignoring: %m");
|
||||||
|
}
|
||||||
|
|
||||||
if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) {
|
if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) {
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1658,3 +1658,63 @@ bool manager_server_is_stub(Manager *m, DnsServer *s) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int socket_disable_pmtud(int fd, int af) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
if (af == AF_UNSPEC) {
|
||||||
|
r = socket_get_family(fd, &af);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (af) {
|
||||||
|
|
||||||
|
case AF_INET: {
|
||||||
|
/* Turn off path MTU discovery, let's rather fragment on the way than to open us up against
|
||||||
|
* PMTU forgery vulnerabilities.
|
||||||
|
*
|
||||||
|
* There appears to be no documentation about IP_PMTUDISC_OMIT, but it has the effect that
|
||||||
|
* the "Don't Fragment" bit in the IPv4 header is turned off, thus enforcing fragmentation if
|
||||||
|
* our datagram size exceeds the MTU of a router in the path, and turning off path MTU
|
||||||
|
* discovery.
|
||||||
|
*
|
||||||
|
* This helps mitigating the PMTUD vulnerability described here:
|
||||||
|
*
|
||||||
|
* https://blog.apnic.net/2019/07/12/its-time-to-consider-avoiding-ip-fragmentation-in-the-dns/
|
||||||
|
*
|
||||||
|
* Similar logic is in place in most DNS servers.
|
||||||
|
*
|
||||||
|
* There are multiple conflicting goals: we want to allow the largest datagrams possible (for
|
||||||
|
* efficiency reasons), but not have fragmentation (for security reasons), nor use PMTUD (for
|
||||||
|
* security reasons, too). Our strategy to deal with this is: use large packets, turn off
|
||||||
|
* PMTUD, but watch fragmentation taking place, and then size our packets to the max of the
|
||||||
|
* fragments seen — and if we need larger packets always go to TCP.
|
||||||
|
*/
|
||||||
|
|
||||||
|
r = setsockopt_int(fd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_OMIT);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AF_INET6: {
|
||||||
|
/* On IPv6 fragmentation only is done by the sender — never by routers on the path. PMTUD is
|
||||||
|
* mandatory. If we want to turn off PMTUD, the only way is by sending with minimal MTU only,
|
||||||
|
* so that we apply maximum fragmentation locally already, and thus PMTUD doesn't happen
|
||||||
|
* because there's nothing that could be fragmented further anymore. */
|
||||||
|
|
||||||
|
r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_MTU, IPV6_MIN_MTU);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -204,3 +204,5 @@ void manager_cleanup_saved_user(Manager *m);
|
|||||||
bool manager_next_dnssd_names(Manager *m);
|
bool manager_next_dnssd_names(Manager *m);
|
||||||
|
|
||||||
bool manager_server_is_stub(Manager *m, DnsServer *s);
|
bool manager_server_is_stub(Manager *m, DnsServer *s);
|
||||||
|
|
||||||
|
int socket_disable_pmtud(int fd, int af);
|
||||||
|
Loading…
Reference in New Issue
Block a user