you have multiple IP addresses. Unix does not provide a way of figuring out what
IP address a packet was sent to when binding to any.
+## `non-local-bind`
+* Boolean
+* Default: no
+
+Bind to addresses even if one or more of the [`local-address`'s](#local-address)
+do not exist on this server. Setting this option will enable the needed socket
+options to allow binding to non-local addresses.
+This feature is intended to facilitate ip-failover setups, but it may also
+mask configuration issues and for this reason it is disabled by default.
+
## `local-address-nonexist-fail`
* Boolean
* Default: no
Local port to bind to.
+## `non-local-bind`
+* Boolean
+* Default: no
+
+Bind to addresses even if one or more of the [`local-address`'s](#local-address)
+do not exist on this server. Setting this option will enable the needed socket
+options to allow binding to non-local addresses.
+This feature is intended to facilitate ip-failover setups, but it may also
+mask configuration issues and for this reason it is disabled by default.
+
## `loglevel`
* Integer between 0 and
* Default: 4
::arg().setSwitch("log-dns-queries","If PDNS should log all incoming DNS queries")="no";
::arg().set("local-address","Local IP addresses to which we bind")="0.0.0.0";
::arg().setSwitch("local-address-nonexist-fail","Fail to start if one or more of the local-address's do not exist on this server")="yes";
+ ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
::arg().set("local-ipv6","Local IP address to which we bind")="";
::arg().setSwitch("reuseport","Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket")="no";
::arg().setSwitch("local-ipv6-nonexist-fail","Fail to start if one or more of the local-ipv6 addresses do not exist on this server")="yes";
d_can_reuseport = false;
#endif
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET, s);
+
locala=ComboAddress(localname, ::arg().asNum("local-port"));
if(locala.sin4.sin_family != AF_INET)
throw PDNSException("Attempting to bind IPv4 socket to IPv6 address");
d_can_reuseport = false;
#endif
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET6, s);
+
if( !d_additional_socket )
g_localaddresses.push_back(locala);
if(::bind(s, (sockaddr*)&locala, sizeof(locala))<0) {
#
# no-shuffle=off
+#################################
+# non-local-bind Enable binding to non-local addresses by using FREEBIND / BINDANY socket options
+#
+# non-local-bind=no
+
#################################
# only-notify Only send AXFR NOTIFY to these IP addresses or netmasks
#
}
#endif
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET, fd);
+
sin.sin4.sin_port = htons(st.port);
int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6);
if (::bind(fd, (struct sockaddr *)&sin, socklen )<0)
void makeUDPServerSockets()
{
+ int one=1;
vector<string>locals;
stringtok(locals,::arg()["local-address"]," ,");
setSocketTimestamps(fd);
if(IsAnyAddress(sin)) {
- int one=1;
setsockopt(fd, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
if(sin.sin6.sin6_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0) {
}
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET6, fd);
+
Utility::setCloseOnExec(fd);
setSocketReceiveBuffer(fd, 250000);
::arg().set("no-shuffle","Don't change")="off";
::arg().set("local-port","port to listen on")="53";
::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
+ ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
::arg().set("daemon","Operate as a daemon")="yes";
::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="4";
exit(1);
}
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET, s);
+
if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
close(s);
if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
L<<Logger::Error<<"Setsockopt failed"<<endl;
exit(1);
}
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET6, s);
if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
}
return true;
}
+void Utility::setBindAny(int af, sock_t sock)
+{
+ int one = 1;
+
+#ifdef IP_FREEBIND
+ if (setsockopt(sock, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
+ theL()<<Logger::Warning<<"Warning: IP_FREEBIND setsockopt failed: "<<strerror(errno)<<endl;
+#endif
+
+#ifdef IP_BINDANY
+ if (af == AF_INET)
+ if (setsockopt(s, IPPROTO_IP, IP_BINDANY, &one, sizeof(one)) < 0)
+ theL()<<Logger::Warning<<"Warning: IP_BINDANY setsockopt failed: "<<strerror(errno)<<endl;
+#endif
+#ifdef IPV6_BINDANY
+ if (af == AF_INET6)
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) < 0)
+ theL()<<Logger::Warning<<"Warning: IPV6_BINDANY setsockopt failed: "<<strerror(errno)<<endl;
+#endif
+#ifdef SO_BINDANY
+ if (setsockopt(sock, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) < 0)
+ theL()<<Logger::Warning<<"Warning: SO_BINDANY setsockopt failed: "<<strerror(errno)<<endl;
+#endif
+}
+
const char *Utility::inet_ntop(int af, const char *src, char *dst, size_t size)
{
return ::inet_ntop(af,src,dst,size);
//! Marks the socket to be closed on exec().
static bool setCloseOnExec ( Utility::sock_t socket );
+
+ //! Sets the socket into Bind-any mode
+ static void setBindAny ( int af, Utility::sock_t socket );
//! Sleeps for a number of seconds.
static unsigned int sleep( unsigned int seconds );