[Dnsmasq-discuss] [PATCH] Bind server sockets to a specific IP address

Sergei Zhirikov sfzhi at yahoo.com
Tue Jun 26 18:20:13 BST 2012


Hi,

The attached patch introduces a new configuration option 'bind-address', 
which tells dnsmasq to bind DNS and TFTP server sockets to a particular 
address (it has no effect if 'bind-interfaces' is specified).
At most one IPv4 and one IPv6 address can be specified. This is useful 
when dnsmasq is running on a host with interfaces continuously coming 
and going (for example a VPN server). 'bind-interfaces' cannot be used 
in that situation for obvious reasons and there is no way to tell 
dnsmasq to respond to DNS queries on those dynamically created 
interfaces, because their names are not known in advance. In addition to 
that this option allows to run other DNS servers (for example as a 
recursive resolver) on the same host, just like with 'bind-interfaces'.

The patch applies cleanly to release 2.62.

Thank you.
--
Kind regards,
Sergei.
-------------- next part --------------
diff -ru dnsmasq-2.62-orig/src/dnsmasq.c dnsmasq-2.62/src/dnsmasq.c
--- dnsmasq-2.62-orig/src/dnsmasq.c	2012-06-04 22:40:11.000000000 +0200
+++ dnsmasq-2.62/src/dnsmasq.c	2012-06-23 11:23:58.695992921 +0200
@@ -1323,7 +1323,7 @@
 	  
 	  if (option_bool(OPT_NOWILD))
 	    iface = listener->iface; /* May be NULL */
-	  else
+	  else if (!using_bind_addr(tcp_addr.sa.sa_family))
 	    {
 	      /* Check for allowed interfaces when binding the wildcard address:
 		 we do this by looking for an interface with the same address as 
@@ -1336,15 +1336,17 @@
 		for (iface = daemon->interfaces; iface; iface = iface->next)
 		  if (sockaddr_isequal(&iface->addr, &tcp_addr))
 		    break;
+
+	      if (!iface)
+		{
+		  shutdown(confd, SHUT_RDWR);
+		  close(confd);
+		  continue;
+		}
 	    }
 	  
-	  if (!iface && !option_bool(OPT_NOWILD))
-	    {
-	      shutdown(confd, SHUT_RDWR);
-	      close(confd);
-	    }
 #ifndef NO_FORK
-	  else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
+	  if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
 	    {
 	      if (p != -1)
 		{
diff -ru dnsmasq-2.62-orig/src/dnsmasq.h dnsmasq-2.62/src/dnsmasq.h
--- dnsmasq-2.62-orig/src/dnsmasq.h	2012-06-04 22:40:11.000000000 +0200
+++ dnsmasq-2.62/src/dnsmasq.h	2012-06-23 11:23:58.695992921 +0200
@@ -754,6 +754,10 @@
   int max_logs;  /* queue limit */
   int cachesize, ftabsize;
   int port, query_port, min_port;
+  struct in_addr *bind_addr;
+#ifdef HAVE_IPV6
+  struct in6_addr *bind_addr6;
+#endif
   unsigned long local_ttl, neg_ttl, max_ttl;
   struct hostsfile *addn_hosts;
   struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
@@ -835,6 +839,12 @@
 
 } *daemon;
 
+#ifdef HAVE_IPV6
+#define using_bind_addr(af) (((af) == AF_INET)? (daemon->bind_addr != NULL): ((af) == AF_INET6)? (daemon->bind_addr6 != NULL): 0)
+#else
+#define using_bind_addr(af) (((af) == AF_INET) && (daemon->bind_addr != NULL))
+#endif
+
 /* cache.c */
 void cache_init(void);
 void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg); 
diff -ru dnsmasq-2.62-orig/src/forward.c dnsmasq-2.62/src/forward.c
--- dnsmasq-2.62-orig/src/forward.c	2012-06-04 22:40:11.000000000 +0200
+++ dnsmasq-2.62/src/forward.c	2012-06-23 15:18:08.428860712 +0200
@@ -765,9 +765,9 @@
 #endif
       
       /* enforce available interface configuration */
-      
-      if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
-	  !iface_check(listen->family, &dst_addr, ifr.ifr_name))
+      if (!using_bind_addr(listen->family) &&
+	  (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
+	   !iface_check(listen->family, &dst_addr, ifr.ifr_name)))
 	return;
       
       if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
diff -ru dnsmasq-2.62-orig/src/network.c dnsmasq-2.62/src/network.c
--- dnsmasq-2.62-orig/src/network.c	2012-06-04 22:40:11.000000000 +0200
+++ dnsmasq-2.62/src/network.c	2012-06-23 11:23:58.695992921 +0200
@@ -495,7 +495,10 @@
   addr.in.sin_len = sizeof(addr.in);
 #endif
   addr.in.sin_family = AF_INET;
-  addr.in.sin_addr.s_addr = INADDR_ANY;
+  if (daemon->bind_addr != NULL)
+    addr.in.sin_addr.s_addr = daemon->bind_addr->s_addr;
+  else
+    addr.in.sin_addr.s_addr = INADDR_ANY;
   addr.in.sin_port = htons(daemon->port);
 
   l = create_listeners(&addr, tftp_enabled, 1);
@@ -506,7 +509,10 @@
   addr.in6.sin6_len = sizeof(addr.in6);
 #  endif
   addr.in6.sin6_family = AF_INET6;
-  addr.in6.sin6_addr = in6addr_any;
+  if (daemon->bind_addr6 != NULL)
+    addr.in6.sin6_addr = *daemon->bind_addr6;
+  else
+    addr.in6.sin6_addr = in6addr_any;
   addr.in6.sin6_port = htons(daemon->port);
   
   if (l) 
diff -ru dnsmasq-2.62-orig/src/option.c dnsmasq-2.62/src/option.c
--- dnsmasq-2.62-orig/src/option.c	2012-06-04 22:40:11.000000000 +0200
+++ dnsmasq-2.62/src/option.c	2012-06-23 11:23:58.695992921 +0200
@@ -119,6 +119,7 @@
 #define LOPT_HOST_REC  308
 #define LOPT_TFTP_LC   309
 #define LOPT_RR        310
+#define LOPT_BIND_ADDR 311
 
 #ifdef HAVE_GETOPT_LONG
 static const struct option opts[] =  
@@ -243,6 +244,7 @@
     { "enable-ra", 0, 0, LOPT_RA },
     { "dhcp-duid", 1, 0, LOPT_DUID },
     { "host-record", 1, 0, LOPT_HOST_REC },
+    { "bind-address", 1, 0, LOPT_BIND_ADDR },
     { NULL, 0, 0, 0 }
   };
 
@@ -374,6 +376,7 @@
   { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
   { LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
   { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
+  { LOPT_BIND_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Specify IP address to bind DNS and TFTP server sockets to."), NULL },
   { 0, 0, NULL, NULL, NULL }
 }; 
 
@@ -1645,6 +1648,49 @@
 	arg = comma;
       } while (arg);
       break;
+      
+    case LOPT_BIND_ADDR:
+      do {
+	struct all_addr bind_addr;
+	comma = split(arg);
+	unhide_metas(arg);
+	if (arg && (bind_addr.addr.addr4.s_addr = inet_addr(arg)) != (in_addr_t)-1)
+	  {
+	    if (daemon->bind_addr != NULL)
+	      {
+		problem = _("multiple IPv4 bind addresses are not supported");
+		break;
+	      }
+	    else
+	      {
+		daemon->bind_addr = opt_malloc(sizeof(struct in_addr));
+		*daemon->bind_addr = bind_addr.addr.addr4;
+	      }
+	  }
+#ifdef HAVE_IPV6
+	else if (arg && inet_pton(AF_INET6, arg, &bind_addr.addr.addr6) > 0)
+	  {
+	    if (daemon->bind_addr6 != NULL)
+	      {
+		problem = _("multiple IPv6 bind addresses are not supported");
+		break;
+	      }
+	    else
+	      {
+		daemon->bind_addr6 = opt_malloc(sizeof(struct in6_addr));
+		*daemon->bind_addr6 = bind_addr.addr.addr6;
+	      }
+	  }
+#endif
+	else
+	  {
+	    option = '?'; /* error */
+	    break;
+	  }
+
+	arg = comma;
+      } while (arg);
+      break;
       
     case 'S':            /*  --server */
     case LOPT_LOCAL:     /*  --local */
diff -ru dnsmasq-2.62-orig/src/tftp.c dnsmasq-2.62/src/tftp.c
--- dnsmasq-2.62-orig/src/tftp.c	2012-06-04 22:40:11.000000000 +0200
+++ dnsmasq-2.62/src/tftp.c	2012-06-23 11:23:58.705993251 +0200
@@ -94,7 +94,7 @@
   if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
     return;
   
-  if (option_bool(OPT_NOWILD))
+  if (option_bool(OPT_NOWILD) || using_bind_addr(listen->family))
     {
       if (listen->iface)
 	{
diff -ru dnsmasq-2.62-orig/man/dnsmasq.8 dnsmasq-2.62/man/dnsmasq.8
--- dnsmasq-2.62-orig/man/dnsmasq.8	2012-06-04 22:40:11.000000000 +0200
+++ dnsmasq-2.62/man/dnsmasq.8	2012-06-23 14:17:07.475451110 +0200
@@ -204,6 +204,20 @@
 same machine. Setting this option also enables multiple instances of
 dnsmasq which provide DHCP service to run in the same machine.
 .TP
+.B \-\^\-bind\-address=<ipaddr>
+Bind DNS and TFTP server sockets to the specified IP address.
+When
+.B \-\^\-bind\-interfaces
+option is not used it may still be desirable to bind DNS and TFTP
+server sockets to a particular non-wildcard address. This option allows
+to do that. At most one IPv4 and one IPv6 address (if built with IPv6
+support) can be specified. When a wildcard address (\fB0.0.0.0\fP for IPv4
+or \fB::\fP for IPv6) is specified with this option dnsmasq will respond
+to any incoming requests regardless of the interface or source IP address.
+When
+.B \-\^\-bind\-interfaces
+option is specified this option has no effect.
+.TP
 .B \-y, --localise-queries
 Return answers to DNS queries from /etc/hosts which depend on the interface over which the query was
 received. If a name in /etc/hosts has more than one address associated with


More information about the Dnsmasq-discuss mailing list