]> git.ipfire.org Git - people/ms/dnsmasq.git/commitdiff
import of dnsmasq-2.11.tar.gz
authorSimon Kelley <simon@thekelleys.org.uk>
Mon, 2 Aug 2004 17:27:27 +0000 (18:27 +0100)
committerSimon Kelley <simon@thekelleys.org.uk>
Thu, 5 Jan 2012 17:31:10 +0000 (17:31 +0000)
CHANGELOG
dnsmasq-rh.spec
dnsmasq-suse.spec
doc.html
src/config.h
src/dhcp.c
src/dnsmasq.c
src/dnsmasq.h
src/forward.c
src/network.c
src/rfc2131.c

index adddf7860465cc35b43594c397e1f6e6d3149973..996765589d04c68c4bd72c4d3608b211ad5eaa77 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1123,4 +1123,23 @@ release 2.10
            support was added. Thanks to Michael Hamilton for
            assistance with this.
 
+version 2.11
+           Fixed DHCP problem which could result in two leases in the
+            database with the same address. This looked much more
+            alarming then it was, since it could only happen when a
+            machine changes MAC address but kept the same name. The
+            old lease would persist until it timed out but things
+            would still work OK. 
+
+           Check that IP addresses in all dhcp-host directives are
+           unique and die horribly if they are not, since otherwise
+           endless protocol loops can occur. 
+           
+           Use IPV6_RECVPKTINFO as socket option rather than
+           IPV6_PKTINFO where available. This keeps late-model FreeBSD
+           happy.
+
+           Set source interface when replying to IPv6 UDP
+           queries. This is needed to cope with link-local addresses.
+
 
index 787886ee814b501f4b36020ea1c4e06fdcf4f9dc..4973d4209a99e0c0bf36200035e3064ad92706e3 100644 (file)
@@ -5,7 +5,7 @@
 ###############################################################################
 
 Name: dnsmasq
-Version: 2.10
+Version: 2.11
 Release: 1
 Copyright: GPL
 Group: System Environment/Daemons
index bc7c34e3dcd3ffded630a3e3f719badc971b2e7b..9899ecf890d73a96ddca118c4899c5ffccf8f7cf 100644 (file)
@@ -5,7 +5,7 @@
 ###############################################################################
 
 Name: dnsmasq
-Version: 2.10
+Version: 2.11
 Release: 1
 Copyright: GPL
 Group: Productivity/Networking/DNS/Servers
index ae8b2057c42b3d28c3c6620290f1f0fb2590434f..8416b84e13b5c69a515669c3500ba0e5ecbb81a2 100644 (file)
--- a/doc.html
+++ b/doc.html
@@ -112,7 +112,9 @@ bzip2 dnsmasq-zzz.tar
 </PRE>
 
 <H2>Links.</H2>
-Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
+Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A
+HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
+and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
 
 <H2>License.</H2>
 Dnsmasq is distributed under the GPL. See the file COPYING in the distribution 
index b072a48fbbf5a67e7ec230e6574972958bbf937e..753dfaa859fc9fb1cbf7187804318a8510244d28 100644 (file)
@@ -12,7 +12,7 @@
 
 /* Author's email: simon@thekelleys.org.uk */
 
-#define VERSION "2.10"
+#define VERSION "2.11"
 
 #define FTABSIZ 150 /* max number of outstanding requests */
 #define MAX_PROCS 20 /* max no children for TCP requests */
index be6855fc252ac63650dc40644d3c3f422ec709c9..f667f95bfa8c3c531ffe41a42f2a990986d0b79d 100644 (file)
 
 #include "dnsmasq.h"
 
-void dhcp_init(int *fdp, int* rfdp)
+void dhcp_init(int *fdp, int* rfdp, struct dhcp_config *configs)
 {
   int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
   struct sockaddr_in saddr;
   int opt = 1;
-  
+  struct dhcp_config *cp;
+
   if (fd == -1)
     die ("cannot create DHCP socket : %s", NULL);
   
@@ -57,6 +58,14 @@ void dhcp_init(int *fdp, int* rfdp)
 #endif
   
   *rfdp = fd;
+
+  /* If the same IP appears in more than one host config, then DISCOVER
+     for one of the hosts will get the address, but REQUEST will be NAKed,
+     since the address is reserved by the other one -> protocol loop. */
+  for (; configs; configs = configs->next)
+    for (cp = configs->next; cp; cp = cp->next)
+      if ((configs->flags & cp->flags & CONFIG_ADDR) &&        configs->addr.s_addr == cp->addr.s_addr)
+       die("Duplicate IP address %s in dhcp-config directive.", inet_ntoa(cp->addr));
 }
 
 void dhcp_packet(struct dhcp_context *contexts, char *packet, 
@@ -370,6 +379,17 @@ int address_available(struct dhcp_context *context, struct in_addr taddr)
 
   return 1;
 }
+struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
+{
+  struct dhcp_config *config;
+  
+  for (config = configs; config; config = config->next)
+    if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
+      return config;
+
+  return NULL;
+}
 
 int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
                     struct in_addr *addrp, unsigned char *hwaddr)   
@@ -377,7 +397,6 @@ int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
   /* Find a free address: exclude anything in use and anything allocated to
      a particular hwaddr/clientid/hostname in our configuration */
 
-  struct dhcp_config *config;
   struct in_addr start, addr ;
   unsigned int i, j;
 
@@ -400,17 +419,10 @@ int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
       addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
 
     
-    if (!lease_find_by_addr(addr))
+    if (!lease_find_by_addr(addr) && !config_find_by_address(configs, addr))
       {
-       for (config = configs; config; config = config->next)
-         if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
-           break;
-       
-       if (!config)
-         {
-           *addrp = addr;
-           return 1;
-         }
+       *addrp = addr;
+       return 1;
       }
   } while (addr.s_addr != start.s_addr);
   
index bd2b72ab253f2f1022f8c111125965f88df68dd6..1b72e16a4095294cce844291e9b62a5fcee784f5 100644 (file)
@@ -206,7 +206,7 @@ int main (int argc, char **argv)
       if (c != 1)
        die("must set exactly one interface on broken systems without IP_RECVIF", NULL);
 #endif
-      dhcp_init(&dhcpfd, &dhcp_raw_fd);
+      dhcp_init(&dhcpfd, &dhcp_raw_fd, dhcp_configs);
       leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
     }
 
index 1f0394a3e8a84884962384bf854b70a661ad669d..4c50bfb915e0f3dec142c90761a5c07558dc8940 100644 (file)
@@ -230,6 +230,7 @@ struct frec {
   union mysockaddr source;
   struct all_addr dest;
   struct server *sentto;
+  unsigned int iface;
   unsigned short orig_id, new_id;
   int fd;
   time_t time;
@@ -412,7 +413,7 @@ struct irec *enumerate_interfaces(struct iname **names,
 struct listener *create_wildcard_listeners(int port);
 struct listener *create_bound_listeners(struct irec *interfaces, int port);
 /* dhcp.c */
-void dhcp_init(int *fdp, int* rfdp);
+void dhcp_init(int *fdp, int* rfdp, struct dhcp_config *configs);
 void dhcp_packet(struct dhcp_context *contexts, char *packet, 
                 struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs, 
                 struct dhcp_vendor *vendors,
@@ -430,7 +431,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
 struct dhcp_config *read_ethers(struct dhcp_config *configs, char *buff);
 void dhcp_update_configs(struct dhcp_config *configs);
 struct dhcp_config *dhcp_read_ethers(struct dhcp_config *configs, char *buff);
-
+struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
 /* lease.c */
 void lease_update_file(int force, time_t now);
 void lease_update_dns(void);
index 4d2354a5f7d293ebafbffba17d234bf0fdc78f3b..b21e9fc5e1f67e7c94f36b7f50d4bef2f742726b 100644 (file)
@@ -36,7 +36,8 @@ void forward_init(int first)
 /* Send a UDP packet with it's source address set as "source" 
    unless nowild is true, when we just send it with the kernel default */
 static void send_from(int fd, int nowild, char *packet, int len, 
-                     union mysockaddr *to, struct all_addr *source)
+                     union mysockaddr *to, struct all_addr *source,
+                     unsigned int iface)
 {
   struct msghdr msg;
   struct iovec iov[1]; 
@@ -94,7 +95,7 @@ static void send_from(int fd, int nowild, char *packet, int len,
       {
        struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
        struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
-       pkt->ipi6_ifindex = 0;
+       pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
        pkt->ipi6_addr = source->addr.addr6;
        msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
        cmptr->cmsg_type = IPV6_PKTINFO;
@@ -191,8 +192,8 @@ unsigned short search_servers(struct server *servers, unsigned int options, stru
 
 /* returns new last_server */  
 static struct server *forward_query(int udpfd, union mysockaddr *udpaddr, 
-                                   struct all_addr *dst_addr, HEADER *header, 
-                                   int plen, unsigned int options, char *dnamebuff, 
+                                   struct all_addr *dst_addr, unsigned int dst_iface,
+                                   HEADER *header, int plen, unsigned int options, char *dnamebuff, 
                                    struct server *servers, struct server *last_server,
                                    time_t now, unsigned long local_ttl)
 {
@@ -246,6 +247,7 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
          
          forward->source = *udpaddr;
          forward->dest = *dst_addr;
+         forward->iface = dst_iface;
          forward->new_id = get_id();
          forward->fd = udpfd;
          forward->orig_id = ntohs(header->id);
@@ -310,7 +312,7 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
   
   /* could not send on, return empty answer or address if known for whole domain */
   plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
-  send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr);
+  send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
   
   return last_server;
 }
@@ -405,7 +407,7 @@ struct server *reply_query(struct serverfd *sfd, int options, char *packet, time
        return NULL;
       
       header->id = htons(forward->orig_id);
-      send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest);
+      send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest, forward->iface);
       forward->new_id = 0; /* cancel */
     }
   
@@ -564,9 +566,9 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
   m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n, 
                      mxnames, mxtarget, options, now, local_ttl, namebuff, edns_pcktsz);
   if (m >= 1)
-    send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
+    send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr, if_index);
   else
-    last_server = forward_query(listen->fd, &source_addr, &dst_addr,
+    last_server = forward_query(listen->fd, &source_addr, &dst_addr, if_index,
                                header, n, options, namebuff, servers, 
                                last_server, now, local_ttl);
   return last_server;
index 4c8c207c371438764e3788db7b7095237e0ed1a3..d0d34e022eb451cbad44ba915173b18bce37ce53 100644 (file)
@@ -263,7 +263,11 @@ static int create_ipv6_listener(struct listener **link, int port)
       setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
       (flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
       fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
+#ifdef IPV6_RECVPKTINFO
+      setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1 ||
+#else
       setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
+#endif
       bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
       listen(tcpfd, 5) == -1 ||
       bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1) 
index b5c25b93d0d1083d61845d385dfd6a8cfca17847..7fb0d1ae3fe92dc53070440e1b4d6640c1471c3e 100644 (file)
@@ -152,8 +152,9 @@ int dhcp_reply(struct dhcp_context *context,
       clid_len = 0;
     }
     
-  if ((config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL)) && 
-      have_config(config, CONFIG_NAME))
+  config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL);
+
+  if (have_config(config, CONFIG_NAME))
     hostname = config->hostname;
   else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
     {
@@ -184,8 +185,16 @@ int dhcp_reply(struct dhcp_context *context,
                    hostname = NULL; /* nothing left */
                }
            }
-         /* search again now we have a hostname */
-         config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
+
+         /* Search again now we have a hostname. 
+            Only accept configs without CLID and HWADDR here, (they won't match)
+            to avoid impersonation by name. */
+         if (!config)
+           {
+             struct dhcp_config *new = find_config(dhcp_configs, context, NULL, 0, mess->chaddr, hostname);
+             if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
+               config = new;
+           }
        }
     }
   
@@ -347,7 +356,8 @@ int dhcp_reply(struct dhcp_context *context,
        mess->yiaddr = config->addr;
       else if (lease && address_available(context, lease->addr))
        mess->yiaddr = lease->addr;
-      else if (opt && address_available(context, addr) && !lease_find_by_addr(addr))
+      else if (opt && address_available(context, addr) && !lease_find_by_addr(addr) && 
+              !config_find_by_address(dhcp_configs, addr))
        mess->yiaddr = addr;
       else if (!address_allocate(context, dhcp_configs, &mess->yiaddr, mess->chaddr))
        message = "no address available";      
@@ -400,12 +410,11 @@ int dhcp_reply(struct dhcp_context *context,
            
          if (!lease)
            { 
-             if ((!address_available(context, mess->yiaddr) || lease_find_by_addr(mess->yiaddr)) && 
-                 (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
-               message = "address unavailable";
+             if (lease_find_by_addr(mess->yiaddr))
+               message = "address in use";
              else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
                message = "no leases left";
-           }
+           } 
        }
       else
        {
@@ -424,29 +433,38 @@ int dhcp_reply(struct dhcp_context *context,
            fuzz = fuzz/2;
        }
       
-      /* If a machine moves networks whilst it has a lease, we catch that here. */
-      if (!message && !is_same_net(mess->yiaddr, context->start, context->netmask))
-       message = "wrong network";
-
-      /* Check for renewal of a lease which is now outside the allowed range. */
-      if (!message && !address_available(context, mess->yiaddr) &&
-         (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
-       message = "address no longer available";
-
-      /* Check if a new static address has been configured. Be very sure that
-        when the client does DISCOVER, it will get the static address, otherwise
-        an endless protocol loop will ensue. */
-      if (!message && have_config(config, CONFIG_ADDR) &&
-         !have_config(config, CONFIG_DISABLE) &&
-         !lease_find_by_addr(config->addr))
-       message = "static lease available";
-   
+      if (!message)
+       {
+         struct dhcp_config *addr_config;
+         /* If a machine moves networks whilst it has a lease, we catch that here. */
+         if (!is_same_net(mess->yiaddr, context->start, context->netmask))
+           message = "wrong network";
+
+         /* Check for renewal of a lease which is now outside the allowed range. */
+         else if (!address_available(context, mess->yiaddr) &&
+                  (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
+           message = "address no longer available";
+
+         /* Check if a new static address has been configured. Be very sure that
+            when the client does DISCOVER, it will get the static address, otherwise
+            an endless protocol loop will ensue. */
+
+         else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
+           message = "static lease available";
+
+         /* Check to see if the address is reserved as a static address for another host */
+         else if ((addr_config = config_find_by_address(dhcp_configs, mess->yiaddr)) && addr_config != config)
+           message ="address reserved";
+       }
+
       log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
       
       if (message)
        {
          log_packet("NAK", &mess->yiaddr, mess->chaddr, iface_name, message);
          
+         lease_prune(lease, now);
+
          mess->siaddr.s_addr = mess->yiaddr.s_addr = mess->ciaddr.s_addr = 0;
          bootp_option_put(mess, NULL, NULL);
          p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);