From e1c959948c0e31d6997bcdfbabfbd077784b2bae Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 17 Jul 2014 01:13:22 +0200 Subject: [PATCH 1/1] resolved: properly handle MTU logic --- src/resolve/resolved-dns-packet.h | 6 +++++- src/resolve/resolved-dns-scope.c | 11 +++++++++++ src/resolve/resolved-link.c | 4 ++++ src/resolve/resolved-link.h | 2 +- src/resolve/resolved-manager.c | 20 ++++++++++++++++++++ src/resolve/resolved.h | 1 + 6 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 99f60a155..de3a789a7 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -44,8 +44,12 @@ struct DnsPacketHeader { /* The various DNS protocols deviate in how large a packet can grow, but the TCP transport has a 16bit size field, hence that appears to - be the maximum. */ + be the absolute maximum. */ #define DNS_PACKET_SIZE_MAX 0xFFFF + +/* RFC 1035 say 512 is the maximum, for classic unicast DNS */ +#define DNS_PACKET_UNICAST_SIZE_MAX 512 + #define DNS_PACKET_SIZE_START 512 struct DnsPacket { diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 0a70cb1f0..a39e705a3 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -102,8 +102,19 @@ int dns_scope_send(DnsScope *s, DnsPacket *p) { return -EMSGSIZE; ifindex = s->link->ifindex; + } else { + uint32_t mtu; + + mtu = manager_find_mtu(s->manager); + if (mtu > 0) { + if (p->size > mtu) + return -EMSGSIZE; + } } + if (p->size > DNS_PACKET_UNICAST_SIZE_MAX) + return -EMSGSIZE; + if (srv->family == AF_INET) r = manager_dns_ipv4_send(s->manager, srv, ifindex, p); else if (srv->family == AF_INET6) diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 9c886a26b..61b112cb0 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -91,6 +91,10 @@ int link_update_rtnl(Link *l, sd_rtnl_message *m) { if (r < 0) return r; + r = sd_rtnl_message_read_u32(m, IFLA_MTU, &l->mtu); + if (r < 0) + return r; + return 0; } diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index 07f68ab41..c0ea2362a 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -58,7 +58,7 @@ struct Link { DnsScope *mdns_ipv4_scope; DnsScope *mdns_ipv6_scope; - size_t mtu; + uint32_t mtu; char *operational_state; diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 5fbb500fd..fed9a7797 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -878,3 +878,23 @@ void manager_next_dns_server(Manager *m) { m->current_dns_server = m->dns_servers; } + +uint32_t manager_find_mtu(Manager *m) { + uint32_t mtu = 0; + Link *l; + Iterator i; + + /* If we don't know on which link a DNS packet would be + * delivered, let's find the largest MTU that works on all + * interfaces we know of */ + + HASHMAP_FOREACH(l, m->links, i) { + if (l->mtu <= 0) + continue; + + if (mtu <= 0 || l->mtu < mtu) + mtu = l->mtu; + } + + return mtu; +} diff --git a/src/resolve/resolved.h b/src/resolve/resolved.h index 438730be6..c592a7e83 100644 --- a/src/resolve/resolved.h +++ b/src/resolve/resolved.h @@ -79,6 +79,7 @@ int manager_write_resolv_conf(Manager *m); DnsServer* manager_find_dns_server(Manager *m, unsigned char family, union in_addr_union *in_addr); DnsServer *manager_get_dns_server(Manager *m); void manager_next_dns_server(Manager *m); +uint32_t manager_find_mtu(Manager *m); int manager_dns_ipv4_fd(Manager *m); int manager_dns_ipv4_send(Manager *m, DnsServer *srv, int ifindex, DnsPacket *p); -- 2.30.2