[Pdns-dev] Better IPv6 support [was: Slaving from IPv6 host]
Lionel Elie Mamane
lionel at mamane.lu
Sat Jan 7 12:02:41 CET 2006
On Tue, Oct 12, 2004 at 03:37:26PM +0200, Lionel Elie Mamane wrote:
> On Sat, Jul 17, 2004 at 05:12:13PM +0200, Lionel Elie Mamane wrote:
>> 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.
And a new version, that additionally corrects the following bug in the
recursor: When AAAA-additional processing is activated, e.g. in an MX
query that answers "example.com IN MX 10 a.mx.example.com", it tries
to lookup a AAAA RR for "10 a.mx.example.com" instead of
"a.mx.example.com".
I've also added the "AI_NUMERICHOST" flag to when I call getaddrinfo.
It also adds an query-local-ipv6 option to choose which IPv6 address
queries will come from (like query-local-address for IPv4).
--
Lionel
-------------- next part --------------
diff --recursive -u pdns-2.9.19/pdns/common_startup.cc pdns-2.9.19.ipv6/pdns/common_startup.cc
--- pdns-2.9.19/pdns/common_startup.cc 2005-10-16 17:26:00.000000000 +0200
+++ pdns-2.9.19.ipv6/pdns/common_startup.cc 2006-01-07 11:06:13.777357810 +0100
@@ -48,6 +48,7 @@
arg().set("local-address","Local IP addresses to which we bind")="0.0.0.0";
arg().set("local-ipv6","Local IP address to which we bind")="";
arg().set("query-local-address","Source IP address for sending queries")="";
+ arg().set("query-local-ipv6","Source IP address for sending queries")="";
arg().set("max-queue-length","Maximum queuelength before considering situation lost")="5000";
arg().set("soa-serial-offset","Make sure that no SOA serial is less than this number")="0";
diff --recursive -u pdns-2.9.19/pdns/communicator.cc pdns-2.9.19.ipv6/pdns/communicator.cc
--- pdns-2.9.19/pdns/communicator.cc 2005-10-20 23:04:07.000000000 +0200
+++ pdns-2.9.19.ipv6/pdns/communicator.cc 2006-01-07 11:06:13.777357810 +0100
@@ -2,6 +2,9 @@
PowerDNS Versatile Database Driven Nameserver
Copyright (C) 2002-2005 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 version 2 as
published by the Free Software Foundation;
@@ -242,7 +245,6 @@
for(vector<DomainInfo>::const_iterator i=sdomains.begin();i!=sdomains.end();++i) {
Resolver resolver;
- resolver.makeUDPSocket();
d_slaveschanged=true;
uint32_t ourserial=i->serial,theirserial=0;
diff --recursive -u pdns-2.9.19/pdns/misc.cc pdns-2.9.19.ipv6/pdns/misc.cc
--- pdns-2.9.19/pdns/misc.cc 2005-10-09 11:57:17.000000000 +0200
+++ pdns-2.9.19.ipv6/pdns/misc.cc 2006-01-07 11:06:13.777357810 +0100
@@ -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.19/pdns/resolver.cc pdns-2.9.19.ipv6/pdns/resolver.cc
--- pdns-2.9.19/pdns/resolver.cc 2005-10-23 18:46:57.000000000 +0200
+++ pdns-2.9.19.ipv6/pdns/resolver.cc 2006-01-07 11:06:13.781358007 +0100
@@ -2,6 +2,9 @@
PowerDNS Versatile Database Driven Nameserver
Copyright (C) 2002 - 2005 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 version 2 as
published by the Free Software Foundation.
@@ -34,35 +37,93 @@
#include "ahuexception.hh"
#include "statbag.hh"
#include "arguments.hh"
+#include <assert.h>
-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 uint16_t port_counter=5000;
port_counter++; // this makes us use a new port for each query, fixes ticket #2
- 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);
- d_sock=socket(AF_INET, type,0);
+ 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(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;
- if(!IpToU32(arg()["query-local-address"], &sin.sin_addr.s_addr))
- throw AhuException("Unable to resolve local address '"+ arg()["query-local-address"] +"'");
+ sa.sa_family = domain;
+
+ if (domain == PF_INET) {
+ struct sockaddr_in &sin = *(struct sockaddr_in*)&ss;
+
+ if(!IpToU32(arg()["query-local-address"], &sin.sin_addr.s_addr))
+ throw AhuException("Unable to resolve local address '"+ arg()["query-local-address"] +"'");
+ ss_size = sizeof(sin);
+ }
+ else if(domain == PF_INET6) {
+ struct addrinfo *toaddrs;
+ struct sockaddr_in6 &sin = *(struct sockaddr_in6*)&ss;
+ sin.sin6_addr = in6addr_any;
+ ss_size = sizeof(sin);
+
+ toaddrs = Utility::resolve_hostname_to_ip(arg()["query-local-ipv6"],"",AF_INET6);
+
+ for(struct addrinfo *toaddr = toaddrs;toaddr!=NULL;toaddr=toaddr->ai_next) {
+ if (toaddr == NULL) {
+ freeaddrinfo(toaddrs);
+ throw AhuException("Unable to resolve local address '"+ arg()["query-local-ipv6"] +"'");
+ }
+ else if (toaddr->ai_addr == NULL || toaddr->ai_family != PF_INET6) {
+ continue;
+ }
+ else {
+ ss_size = toaddr->ai_addrlen;
+ memcpy(&(sin.sin6_addr), toaddr->ai_addr, ss_size);
+ freeaddrinfo(toaddrs);
+ break;
+ }
+ }
+ }
+ else {
+ throw AhuException("Unkown socket domain: " + domain);
+ }
int tries=10;
while(--tries) {
- sin.sin_port = htons(10000+(random()%10000));
-
- if (bind(d_sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+ 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, &sa, ss_size) >= 0)
break;
}
@@ -163,8 +224,7 @@
d_type=type;
d_inaxfr=false;
- struct sockaddr_in toaddr;
- struct in_addr inp;
+ struct addrinfo *toaddrs;
ServiceTuple st;
st.port=53;
try {
@@ -174,15 +234,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)
@@ -211,7 +282,6 @@
int Resolver::resolve(const string &ip, const char *domain, int type)
{
- makeUDPSocket();
sendResolve(ip,domain,type);
try {
struct sockaddr_in from;
@@ -224,25 +294,16 @@
}
-void Resolver::makeTCPSocket(const string &ip, uint16_t port)
+void Resolver::makeTCPSocket_one_IP(const struct sockaddr *toaddr, const size_t toaddr_len)
{
- if(d_sock>=0)
- return;
-
- struct in_addr inp;
- Utility::inet_aton(ip.c_str(),&inp);
- d_toaddr.sin_addr.s_addr=inp.s_addr;
-
- d_toaddr.sin_port=htons(port);
- d_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!="") {
+ if (querylocaladdress!="" && toaddr->sa_family == AF_INET) {
struct sockaddr_in fromaddr;
struct hostent *h=0;
@@ -268,9 +329,9 @@
int err;
#ifndef WIN32
- if((err=connect(d_sock,(struct sockaddr*)&d_toaddr,sizeof(d_toaddr)))<0 && errno!=EINPROGRESS) {
+ if((err=connect(d_sock,toaddr,toaddr_len))<0 && errno!=EINPROGRESS) {
#else
- if((err=connect(d_sock,(struct sockaddr*)&d_toaddr,sizeof(d_toaddr)))<0 && WSAGetLastError() != WSAEWOULDBLOCK ) {
+ if((err=connect(d_sock,toaddr,toaddr_len))<0 && WSAGetLastError() != WSAEWOULDBLOCK ) {
#endif // WIN32
Utility::closesocket(d_sock);
d_sock=-1;
@@ -315,6 +376,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.19/pdns/resolver.hh pdns-2.9.19.ipv6/pdns/resolver.hh
--- pdns-2.9.19/pdns/resolver.hh 2005-10-23 18:39:46.000000000 +0200
+++ pdns-2.9.19.ipv6/pdns/resolver.hh 2006-01-07 11:06:13.781358007 +0100
@@ -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
@@ -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, uint16_t port=53);
int notify(int sock, const string &domain, const string &ip, uint16_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.19/pdns/syncres.cc pdns-2.9.19.ipv6/pdns/syncres.cc
--- pdns-2.9.19/pdns/syncres.cc 2005-10-23 13:32:01.000000000 +0200
+++ pdns-2.9.19.ipv6/pdns/syncres.cc 2006-01-07 11:31:26.199843526 +0100
@@ -2,6 +2,11 @@
PowerDNS Versatile Database Driven Nameserver
Copyright (C) 2003 - 2005 PowerDNS.COM BV
+ Copyright (C) 2006 Lionel Elie Mamane <lionel at mamane.lu>
+
+ Modified 7 Jan 2006 by Lionel Elie Mamane <lionel at mamane.lu>
+ Chop off priority of and canonicalise AAAA additional processing RRs, too.
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as published
by the Free Software Foundation
@@ -585,18 +590,20 @@
((k->d_place==DNSResourceRecord::AUTHORITY || k->d_place==DNSResourceRecord::ANSWER) && k->qtype==QType(QType::NS))) {
LOG<<d_prefix<<qname<<": record '"<<k->content<<"|"<<k->qtype.getName()<<"' needs IP for additional processing"<<endl;
set<GetBestNSAnswer>beenthere;
+ string RR_to_lookup;
if(k->qtype==QType(QType::MX)) {
string::size_type pos=k->content.find_first_not_of(" \t0123456789"); // chop off the priority
if(pos!=string::npos)
- doResolve(toLowerCanonic(k->content.substr(pos)), QType(QType::A),addit,1,beenthere);
+ RR_to_lookup = toLowerCanonic(k->content.substr(pos));
else
- doResolve(toLowerCanonic(k->content), QType(QType::A),addit,1,beenthere);
+ RR_to_lookup = toLowerCanonic(k->content);
}
else
- doResolve(k->content,QType(QType::A),addit,1,beenthere);
+ RR_to_lookup = k->content;
+ doResolve(RR_to_lookup,QType(QType::A),addit,1,beenthere);
if(arg().mustDo("aaaa-additional-processing"))
- doResolve(k->content,QType(QType::AAAA),addit,1,beenthere);
+ doResolve(RR_to_lookup,QType(QType::AAAA),addit,1,beenthere);
}
for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {
diff --recursive -u pdns-2.9.19/pdns/unix_utility.cc pdns-2.9.19.ipv6/pdns/unix_utility.cc
--- pdns-2.9.19/pdns/unix_utility.cc 2005-10-20 23:45:04.000000000 +0200
+++ pdns-2.9.19.ipv6/pdns/unix_utility.cc 2006-01-07 11:28:21.910767814 +0100
@@ -2,6 +2,9 @@
PowerDNS Versatile Database Driven Nameserver
Copyright (C) 2002 - 2005 PowerDNS.COM BV
+ Modified 10-17 Jul 2004, 2005 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 version 2 as
published by the Free Software Foundation
@@ -27,6 +30,7 @@
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
+#include <netdb.h>
#ifdef NEED_INET_NTOP_PROTO
extern "C" {
@@ -123,6 +127,28 @@
}
+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;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ 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.19/pdns/utility.hh pdns-2.9.19.ipv6/pdns/utility.hh
--- pdns-2.9.19/pdns/utility.hh 2005-09-03 20:12:43.000000000 +0200
+++ pdns-2.9.19.ipv6/pdns/utility.hh 2006-01-07 11:06:13.781358007 +0100
@@ -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