]> granicus.if.org Git - pdns/commitdiff
Ignore Path MTU Discovery on UDP server socket
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 21 Jan 2019 14:40:38 +0000 (15:40 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 18 Apr 2019 09:59:50 +0000 (11:59 +0200)
It might help prevent Path MTU poisoning attacks.

pdns/dnsdist.cc
pdns/iputils.cc
pdns/iputils.hh
pdns/nameserver.cc
pdns/pdns_recursor.cc

index f7bfc1dee545f193182f8a758dbdfe520783a99c..64196d6fc63e74201dfe7abae01d389ee3cd3b57 100644 (file)
@@ -2218,6 +2218,17 @@ static void setUpLocalBind(std::unique_ptr<ClientState>& cs)
 #endif
   }
 
+  if (!cs->tcp) {
+    if (cs->local.isIPv4()) {
+      try {
+        setSocketIgnorePMTU(cs->udpFD);
+      }
+      catch(const std::exception& e) {
+        warnlog("Failed to set IP_MTU_DISCOVER on UDP server socket for local address '%s': %s", cs->local.toStringWithPort(), e.what());
+      }
+    }
+  }
+
   const std::string& itf = cs->interface;
   if (!itf.empty()) {
 #ifdef SO_BINDTODEVICE
index 84425e66cb08514ecbacfdb92e716f266b77d91f..de94bb2e5f6de58362e179f6f0c302347b63d5dd 100644 (file)
@@ -136,6 +136,25 @@ int SSetsockopt(int sockfd, int level, int opname, int value)
   return ret;
 }
 
+void setSocketIgnorePMTU(int sockfd)
+{
+#ifdef IP_PMTUDISC_OMIT
+  /* Linux 3.15+ has IP_PMTUDISC_OMIT, which discards PMTU information to prevent
+     poisoning, but still allows fragmentation if the packet size exceeds the
+     outgoing interface MTU, which is good.
+  */
+  try {
+    SSetsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_OMIT);
+    return;
+  }
+  catch(const std::exception& e) {
+    /* failed, let's try IP_PMTUDISC_DONT instead */
+  }
+#endif /* IP_PMTUDISC_OMIT */
+
+  /* IP_PMTUDISC_DONT disables Path MTU discovery */
+  SSetsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DONT);
+}
 
 bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv) 
 {
index 694c6474015f785caa6aa00f8c21926cb8d9a812..457b2b5971e332357275058bb2912d14167e24a0 100644 (file)
@@ -1046,6 +1046,7 @@ int SBind(int sockfd, const ComboAddress& local);
 int SAccept(int sockfd, ComboAddress& remote);
 int SListen(int sockfd, int limit);
 int SSetsockopt(int sockfd, int level, int opname, int value);
+void setSocketIgnorePMTU(int sockfd);
 
 #if defined(IP_PKTINFO)
   #define GEN_IP_PKTINFO IP_PKTINFO
index 99542014416e013172b315de32bc043e3bbb8d2b..55812391712774d76a0ad99c7365ad57e94bac66 100644 (file)
@@ -123,6 +123,15 @@ void UDPNameserver::bindIPv4()
     if (!setSocketTimestamps(s))
       g_log<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
 
+    if (locala.isIPv4()) {
+      try {
+        setSocketIgnorePMTU(s);
+      }
+      catch(const std::exception& e) {
+        g_log<<Logger::Warning<<"Failed to set IP_MTU_DISCOVER on UDP server socket: "<<e.what()<<endl;
+      }
+    }
+
 #ifdef SO_REUSEPORT
     if( d_can_reuseport )
         if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
index a0dda978a0851ca446c24f235d6094d84b471fa3..832643a049712cbd22c43f0849125fe8b06f5ef7 100644 (file)
@@ -2565,7 +2565,17 @@ static void makeUDPServerSockets(deferredAdd_t& deferredAdds)
         throw PDNSException("SO_REUSEPORT: "+stringerror());
     }
 #endif
-  socklen_t socklen=sin.getSocklen();
+
+    if (sin.isIPv4()) {
+      try {
+        setSocketIgnorePMTU(fd);
+      }
+      catch(const std::exception& e) {
+        g_log<<Logger::Warning<<"Failed to set IP_MTU_DISCOVER on UDP server socket: "<<e.what()<<endl;
+      }
+    }
+
+    socklen_t socklen=sin.getSocklen();
     if (::bind(fd, (struct sockaddr *)&sin, socklen)<0)
       throw PDNSException("Resolver binding to server socket on port "+ std::to_string(st.port) +" for "+ st.host+": "+stringerror());