chiark / gitweb /
resolved: properly handle MTU logic
authorLennart Poettering <lennart@poettering.net>
Wed, 16 Jul 2014 23:13:22 +0000 (01:13 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 16 Jul 2014 23:41:52 +0000 (01:41 +0200)
src/resolve/resolved-dns-packet.h
src/resolve/resolved-dns-scope.c
src/resolve/resolved-link.c
src/resolve/resolved-link.h
src/resolve/resolved-manager.c
src/resolve/resolved.h

index 99f60a1..de3a789 100644 (file)
@@ -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 {
index 0a70cb1..a39e705 100644 (file)
@@ -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)
index 9c886a2..61b112c 100644 (file)
@@ -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;
 }
 
index 07f68ab..c0ea236 100644 (file)
@@ -58,7 +58,7 @@ struct Link {
         DnsScope *mdns_ipv4_scope;
         DnsScope *mdns_ipv6_scope;
 
-        size_t mtu;
+        uint32_t mtu;
 
         char *operational_state;
 
index 5fbb500..fed9a77 100644 (file)
@@ -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;
+}
index 438730b..c592a7e 100644 (file)
@@ -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);