summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-07-17 01:13:22 +0200
committerLennart Poettering <lennart@poettering.net>2014-07-17 01:41:52 +0200
commite1c959948c0e31d6997bcdfbabfbd077784b2bae (patch)
tree20110fde60bc894123285e77c329c22ec3a0d8b4
parent76f468c8ea568fce98fa75d7f1d540256eb0940a (diff)
resolved: properly handle MTU logic
-rw-r--r--src/resolve/resolved-dns-packet.h6
-rw-r--r--src/resolve/resolved-dns-scope.c11
-rw-r--r--src/resolve/resolved-link.c4
-rw-r--r--src/resolve/resolved-link.h2
-rw-r--r--src/resolve/resolved-manager.c20
-rw-r--r--src/resolve/resolved.h1
6 files changed, 42 insertions, 2 deletions
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index 99f60a1556..de3a789a78 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 0a70cb1f0f..a39e705a3b 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 9c886a26b5..61b112cb05 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 07f68ab41c..c0ea2362ab 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 5fbb500fd0..fed9a77973 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 438730be6e..c592a7e833 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);