[Pdns-dev] Slaving from IPv6 host

Lionel Elie Mamane lionel at mamane.lu
Tue Oct 12 16:37:26 CEST 2004


On Sat, Jul 17, 2004 at 05:12:13PM +0200, Lionel Elie Mamane wrote:
> (This is a continuation to
>  http://mailman.powerdns.com/pipermail/pdns-users/2004-July/001766.html
> )

> pdsn 2.9.16 cannot slave from an IPv6 host. Here's a patch that
> implements this.

In case anyone is interested, a new version of the patch, that makes
IPv6 literals in masters (masters from which to slave from) work. In
this case, a "." is used as IP address-to-port separator.

-- 
Lionel
-------------- next part --------------
diff --recursive -u pdns-2.9.16/pdns/communicator.cc pdns-2.9.16.lio/pdns/communicator.cc
--- pdns-2.9.16/pdns/communicator.cc	2003-05-25 14:38:48.000000000 +0200
+++ pdns-2.9.16.lio/pdns/communicator.cc	2004-10-11 20:57:15.000000000 +0200
@@ -2,6 +2,9 @@
     PowerDNS Versatile Database Driven Nameserver
     Copyright (C) 2002  PowerDNS.COM BV
 
+    Modified 10-17 Jul 2004 for slaving from IPv6 host by
+    Lionel Elie Mamane <lionel at mamane.lu>
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -241,7 +244,6 @@
       " checking"<<endl;
 
   Resolver resolver;
-  resolver.makeUDPSocket();
   for(vector<DomainInfo>::const_iterator i=sdomains.begin();i!=sdomains.end();++i) {
     d_slaveschanged=true;
     u_int32_t ourserial=i->serial,theirserial=0;
diff --recursive -u pdns-2.9.16/pdns/misc.cc pdns-2.9.16.lio/pdns/misc.cc
--- pdns-2.9.16/pdns/misc.cc	2004-02-04 21:20:23.000000000 +0100
+++ pdns-2.9.16.lio/pdns/misc.cc	2004-10-11 21:01:00.000000000 +0200
@@ -2,6 +2,9 @@
     PowerDNS Versatile Database Driven Nameserver
     Copyright (C) 2002  PowerDNS.COM BV
 
+    Modified 11 Oct 2004 for slaving from IPv6 host by
+    Lionel Elie Mamane <lionel at mamane.lu>
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -139,9 +142,21 @@
 
 void parseService(const string &descr, ServiceTuple &st)
 {
-
+  // If descr contains at least two colons (:), it is an IPv6 address litteral.
+  // If not, it cannot be.
+  const string colon = ":";
+  string delimiter = colon;
+  {
+    string::size_type i;
+    i = descr.find_first_of(colon);
+    if (i != string::npos) {
+      if (descr.find_first_of(colon,i+1) != string::npos) {
+	delimiter = ".";
+      }
+    }
+  }
   vector<string>parts;
-  stringtok(parts,descr,":");
+  stringtok(parts,descr,delimiter.c_str());
   if(parts.empty())
     throw AhuException("Unable to parse '"+descr+"' as a service");
   st.host=parts[0];
diff --recursive -u pdns-2.9.16/pdns/resolver.cc pdns-2.9.16.lio/pdns/resolver.cc
--- pdns-2.9.16/pdns/resolver.cc	2003-10-11 21:27:14.000000000 +0200
+++ pdns-2.9.16.lio/pdns/resolver.cc	2004-10-11 20:57:05.000000000 +0200
@@ -2,6 +2,9 @@
     PowerDNS Versatile Database Driven Nameserver
     Copyright (C) 2002  PowerDNS.COM BV
 
+    Modified 10-17 Jul 2004 for slaving from IPv6 host by
+    Lionel Elie Mamane <lionel at mamane.lu>
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -35,36 +38,78 @@
 #include "ahuexception.hh"
 #include "statbag.hh"
 #include "arguments.hh"
+#include <sstream>
+#include <cassert>
 
-void Resolver::makeUDPSocket()
+void Resolver::makeUDPSocket(int domain)
 {
-  makeSocket(SOCK_DGRAM);
+  makeSocket(domain, SOCK_DGRAM);
 }
 
-void Resolver::makeSocket(int type)
+void Resolver::makeSocket(int domain, int type)
 {
   static u_int16_t port_counter=5000;
-  if(d_sock>0)
-    return;
+  struct sockaddr_storage ss;
+  socklen_t ss_size = sizeof(ss);
+  struct sockaddr &sa = *(struct sockaddr*)&ss;
+
+  memset((char *)&ss,0, sizeof(ss));
+
+  assert(AF_INET == PF_INET && AF_INET6 == PF_INET6);
+
+  if(d_sock > 0) {
+    int result;
+
+    result = getsockname(d_sock, &sa, &ss_size);
+    if (result != 0 || sa.sa_family != domain) {
+      memset((char *)&ss,0, sizeof(ss));
+      Utility::closesocket(d_sock);
+    }
+    else {
+      return;
+    }
+  }
 
-  d_sock=socket(AF_INET, type,0);
+  d_sock=socket(domain, type,0);
   if(d_sock<0) 
     throw AhuException("Making a socket for resolver: "+stringerror());
 
-  struct sockaddr_in sin;
-  memset((char *)&sin,0, sizeof(sin));
-  
-  sin.sin_family = AF_INET;
-  sin.sin_addr.s_addr = INADDR_ANY;
+  sa.sa_family = domain;
+
+  if (domain == PF_INET) {
+    struct sockaddr_in &sin = *(struct sockaddr_in*)&ss;
+
+    sin.sin_addr.s_addr = INADDR_ANY;
+    ss_size = sizeof(sin);
+  }
+  else if(domain == PF_INET6) {
+    struct sockaddr_in6 &sin = *(struct sockaddr_in6*)&ss;
+
+    sin.sin6_addr = in6addr_any;
+    ss_size = sizeof(sin);
+  }
+  else {
+    throw AhuException("Unkown socket domain: " + domain);
+  }
 
   int tries=10;
   while(--tries) {
-    sin.sin_port = htons(10000+(port_counter++)%10000); // should be random!
+    if (domain == PF_INET) {
+      struct sockaddr_in &sin = *(struct sockaddr_in*)&ss;
+
+      sin.sin_port = htons(10000+(port_counter++)%10000); // should be random!
+    }
+    else if(domain == PF_INET6) {
+      struct sockaddr_in6 &sin = *(struct sockaddr_in6*)&ss;
+
+      sin.sin6_port = htons(10000+(port_counter++)%10000); // should be random!
+    }
   
-    if (bind(d_sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 
+    if (bind(d_sock, &sa, ss_size) >= 0)
       break;
 
   }
+
   if(!tries)
     throw AhuException("Resolver binding to local socket: "+stringerror());
 }
@@ -159,8 +204,7 @@
   d_type=type;
   d_inaxfr=false;
 
-  struct sockaddr_in toaddr;
-  struct in_addr inp;
+  struct addrinfo *toaddrs;
   ServiceTuple st;
   st.port=53;
   try {
@@ -170,15 +214,26 @@
     throw ResolverException("Sending a dns question to '"+ip+"': "+ae.reason);
   }
 
-  Utility::inet_aton(st.host.c_str(),&inp);
-  toaddr.sin_addr.s_addr=inp.s_addr;
-
-  toaddr.sin_port=htons(st.port);
-  toaddr.sin_family=AF_INET;
+  {
+    ostringstream ss;
+    ss << st.port;
+    toaddrs = Utility::resolve_hostname_to_ip(st.host.c_str(),ss.str(),AF_UNSPEC);
+  }
 
-  if(sendto(d_sock, p.getData(), p.len, 0, (struct sockaddr*)(&toaddr), sizeof(toaddr))<0) {
-    throw ResolverException("Unable to ask query of "+st.host+":"+itoa(st.port)+": "+stringerror());
+  for(struct addrinfo *toaddr = toaddrs;toaddr!=NULL;toaddr=toaddr->ai_next) {
+    makeUDPSocket(toaddr->ai_addr->sa_family);
+    if(sendto(d_sock, p.getData(), p.len, 0, toaddr->ai_addr, toaddr->ai_addrlen)<0) {
+      if (toaddr->ai_next == NULL) {
+	freeaddrinfo(toaddrs);
+	throw ResolverException("Unable to ask query of "+st.host+":"+itoa(st.port)+": "+stringerror());
+      }
+    }
+    else
+      break;
   }
+
+  freeaddrinfo(toaddrs);
+
 }
 
 int Resolver::receiveResolve(struct sockaddr* fromaddr, Utility::socklen_t addrlen)
@@ -207,7 +262,6 @@
   
 int Resolver::resolve(const string &ip, const char *domain, int type)
 {
-  makeUDPSocket();
   sendResolve(ip,domain,type);
   try {
     struct sockaddr_in from;
@@ -220,23 +274,13 @@
   
 }
 
-void Resolver::makeTCPSocket(const string &ip, u_int16_t port)
+void Resolver::makeTCPSocket_one_IP(const struct sockaddr *toaddr, const size_t toaddr_len)
 {
-  if(d_sock>=0)
-    return;
-  struct sockaddr_in toaddr;
-  struct in_addr inp;
-  Utility::inet_aton(ip.c_str(),&inp);
-  toaddr.sin_addr.s_addr=inp.s_addr;
-
-  toaddr.sin_port=htons(port);
-  toaddr.sin_family=AF_INET;
-  
-
-  d_sock=socket(AF_INET,SOCK_STREAM,0);
+  d_sock=socket(toaddr->sa_family,SOCK_STREAM,0);
   if(d_sock<0)
     throw ResolverException("Unable to make a TCP socket for resolver: "+stringerror());
 
+  // TODO: Handle IPv6 here
   // Use query-local-address as source IP for queries, if specified.
   string querylocaladdress(arg()["query-local-address"]);
   if (querylocaladdress!="") {
@@ -265,9 +309,9 @@
 
   int err;
 #ifndef WIN32
-  if((err=connect(d_sock,(struct sockaddr*)&toaddr,sizeof(toaddr)))<0 && errno!=EINPROGRESS) {
+  if((err=connect(d_sock,toaddr,toaddr_len))<0 && errno!=EINPROGRESS) {
 #else
-  if((err=connect(d_sock,(struct sockaddr*)&toaddr,sizeof(toaddr)))<0 && WSAGetLastError() != WSAEWOULDBLOCK ) {
+  if((err=connect(d_sock,toaddr,toaddr_len))<0 && WSAGetLastError() != WSAEWOULDBLOCK ) {
 #endif // WIN32
     throw ResolverException("connect: "+stringerror());
   }
@@ -310,6 +354,33 @@
   // d_sock now connected
 }
 
+void Resolver::makeTCPSocket(const string &ip, u_int16_t port)
+{
+  if(d_sock>=0)
+    return;
+  struct addrinfo *toaddrs;
+  {
+    ostringstream ss;
+    ss << port;
+    toaddrs = Utility::resolve_hostname_to_ip(ip,ss.str(),AF_UNSPEC);
+  }
+
+  if (toaddrs==NULL)
+    throw ResolverException("unable to resolve "+ip);
+
+  for(struct addrinfo *toaddr = toaddrs;toaddr!=NULL;toaddr=toaddr->ai_next) {
+    try {
+      makeTCPSocket_one_IP(toaddr->ai_addr, toaddr->ai_addrlen);
+    }
+    catch(...){
+      if (toaddr->ai_next==NULL) {
+	freeaddrinfo(toaddrs);
+	throw;
+      }
+    }
+  }
+  freeaddrinfo(toaddrs);
+}
 
 //! returns -1 for permanent error, 0 for timeout, 1 for success
 int Resolver::axfr(const string &ip, const char *domain)
diff --recursive -u pdns-2.9.16/pdns/resolver.hh pdns-2.9.16.lio/pdns/resolver.hh
--- pdns-2.9.16/pdns/resolver.hh	2003-05-25 13:46:07.000000000 +0200
+++ pdns-2.9.16.lio/pdns/resolver.hh	2004-07-17 16:47:49.000000000 +0200
@@ -2,6 +2,9 @@
     PowerDNS Versatile Database Driven Nameserver
     Copyright (C) 2002  PowerDNS.COM BV
 
+    Modified 10-17 Jul 2004 for slaving from IPv6 host by
+    Lionel Elie Mamane <lionel at mamane.lu>
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -16,25 +19,25 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-
+
 #include <string>
 #include <vector>
-#include <sys/types.h>
-
-#ifndef WIN32
-
-# include <arpa/nameser.h>
-# include <resolv.h>
-# include <netdb.h> 
-# include <unistd.h>
-# include <sys/time.h>
-# include <sys/uio.h>
-# include <fcntl.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
+#include <sys/types.h>
+
+#ifndef WIN32
+
+# include <arpa/nameser.h>
+# include <resolv.h>
+# include <netdb.h> 
+# include <unistd.h>
+# include <sys/time.h>
+# include <sys/uio.h>
+# include <fcntl.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
 # undef res_mkquery
-#endif // WIN32
+#endif // WIN32
 
 #include "ahuexception.hh"
 #include "dns.hh"
@@ -55,8 +58,8 @@
   string i;
 
   typedef vector<DNSResourceRecord> res_t;
-  void makeSocket(int type);
-  void makeUDPSocket();
+  void makeSocket(int domain, int type);
+  void makeUDPSocket(int domain);
   void makeTCPSocket(const string &ip, u_int16_t port=53);
   int notify(int sock, const string &domain, const string &ip, u_int16_t id);
   int resolve(const string &ip, const char *domain, int type);
@@ -74,6 +77,7 @@
   int axfr(const string &ip, const char *domain);
   
 private:
+  void Resolver::makeTCPSocket_one_IP(const struct sockaddr *toaddr, const size_t toaddr_len);
   void timeoutReadn(char *buffer, int bytes);
   int d_sock;
   unsigned char *d_buf;
diff --recursive -u pdns-2.9.16/pdns/unix_utility.cc pdns-2.9.16.lio/pdns/unix_utility.cc
--- pdns-2.9.16/pdns/unix_utility.cc	2003-10-04 15:18:25.000000000 +0200
+++ pdns-2.9.16.lio/pdns/unix_utility.cc	2004-07-17 16:48:27.000000000 +0200
@@ -2,6 +2,9 @@
     PowerDNS Versatile Database Driven Nameserver
     Copyright (C) 2002  PowerDNS.COM BV
 
+    Modified 10-17 Jul 2004 by Lionel Elie Mamane <lionel at mamane.lu>
+    Added resolve_hostname_to_ip function.
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -29,6 +32,7 @@
 #include <pwd.h>
 #include <grp.h>
 #include <sys/types.h>
+#include <netdb.h>
 
 #ifdef NEED_INET_NTOP_PROTO
 extern "C" {
@@ -122,6 +126,27 @@
 
 }
 
+struct addrinfo *Utility::resolve_hostname_to_ip( const string &host, const string &port, int pf )
+{
+   struct addrinfo hints, *res0;
+   int result;
+   memset(&hints, 0, sizeof(hints));
+   hints.ai_family = pf;
+   hints.ai_socktype = SOCK_STREAM;
+
+   result = getaddrinfo(host.c_str(), port.c_str(), &hints, &res0);
+   if ( result != 0 ) {
+     theL()<<Logger::Error<<"Unable to resolve hostname '"<<host<<"': "<<gai_strerror(result)<<endl;
+     if (result == EAI_SYSTEM)
+       theL()<<Logger::Error<<"The system error is: "<<strerror(errno)<<endl;
+     return NULL;
+   }
+   else
+     if (res0==0)
+       theL()<<Logger::Error<<"Unable to resolve hostname '"<<host<<"': "<<"Success, but no information returned"<<endl;
+
+   return res0;
+}
 
 // Converts an address from presentation format to network format.
 int Utility::inet_pton( int af, const char *src, void *dst )
diff --recursive -u pdns-2.9.16/pdns/utility.hh pdns-2.9.16.lio/pdns/utility.hh
--- pdns-2.9.16/pdns/utility.hh	2003-11-30 11:53:06.000000000 +0100
+++ pdns-2.9.16.lio/pdns/utility.hh	2004-07-17 16:50:35.000000000 +0200
@@ -2,6 +2,9 @@
     PowerDNS Versatile Database Driven Nameserver
     Copyright (C) 2002  PowerDNS.COM BV
 
+    Modified 10-17 Jul 2004 by Lionel Elie Mamane <lionel at mamane.lu>
+    Added resolve_hostname_to_ip function.
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -188,6 +191,9 @@
   //! Gets the current time.
   static int gettimeofday( struct timeval *tv, void *tz = NULL );
 
+  //! Converts an address from any format to binary data.
+  static struct addrinfo *resolve_hostname_to_ip( const string &host, const string &port, int pf );
+
   //! Converts an address from dot and numbers format to binary data.
   static int inet_aton( const char *cp, struct in_addr *inp );
 


More information about the Pdns-dev mailing list