]> git.ipfire.org Git - people/ms/dnsmasq.git/commitdiff
import of dnsmasq-2.7.tar.gz
authorSimon Kelley <simon@thekelleys.org.uk>
Fri, 23 Apr 2004 21:21:21 +0000 (22:21 +0100)
committerSimon Kelley <simon@thekelleys.org.uk>
Thu, 5 Jan 2012 17:31:10 +0000 (17:31 +0000)
14 files changed:
CHANGELOG
dnsmasq-rh.spec
dnsmasq-suse.spec
dnsmasq.8
dnsmasq.conf.example
src/config.h
src/dhcp.c
src/dnsmasq.c
src/dnsmasq.h
src/network.c
src/option.c
src/rfc1035.c
src/rfc2131.c
src/util.c

index 0a9caa71259a5392c1f0b53ce3c639b1b1fd3fb0..27edc3318deec14f5f796d2062cefa91e68349be 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -916,12 +916,49 @@ release 2.6
             comment, a '#' character must now be a the start of a
             line or preceded by whitespace. Thanks to Christian
             Haggstrom for the bug report.
-            
 
+release 2.7  
+             Allow the dhcp-host specification of id:* which makes 
+            dnsmasq ignore any client-id. This is useful to ensure 
+            that a dual-boot machine sees the same lease when one OS 
+            gives a client-id and the other doesn't. It's also useful
+            when PXE boot DHCP does not use client IDs but the OS it boots 
+             does. Thanks to Grzegorz Nosek for suggesting this enhancement.
 
+            No longer assume that ciaddr is zero in received DHCPDISCOVER 
+            messages, just for security against broken clients.
 
+            Set default of siaddr field to the address of the machine running 
+             dnsmasq when not explicitly set using dhcp-boot
+             option. This is the ISC dhcpd behaviour.  
 
-            
+             Send T1 and T2 options in DHCPOFFER packets. This is required
+            by the DHCP client in some JetDirect printers. Thanks 
+             to Paul Mattal for work on this.
+
+            Fixed bug with DHCP on OpenBSD reported by Dominique Jacquel.
+            The code which added loopback interfaces to the list
+            was confusing the DHCP code, which expected one interface only.
+            Solved by adding loopback interfaces to address list instead.
 
+            Add dhcp-vendorclass option to allow options to be sent only
+            to certain classes of clients.
+
+            Tweaked option search code so that if a netid-qualified
+            option is used, any unqualified option is ignored.
             
+            Changed the method of picking new dynamic IP
+            addresses. This used to use the next consecutive
+            address as long it was free, now it uses a hash
+            from the client hardware address. This reduces the amount
+            of address movement for clients which let their lease
+            expire and allows consecutive DHCPOFFERS to the same host
+            to (almost always) be for the same address, without
+            storing state before a lease is granted.
+            Tweaked option handling code to return all possible
+            options rather than none when DHCP "requested options"
+            field is missing. This fixes interoperability with
+            ancient IBM LANMAN DHCP clients. Thanks to Jim Louvau for
+            help with this.
+
index 847a267202f0b61923d9b4f096b9de966f3acdc4..59982aec254232ef6a68a26435431a37f18a6fa4 100644 (file)
@@ -5,7 +5,7 @@
 ###############################################################################
 
 Name: dnsmasq
-Version: 2.6
+Version: 2.7
 Release: 1
 Copyright: GPL
 Group: System Environment/Daemons
index 984cb3e8bab56fe5ad42a0eeafbdc538448b3c34..9268a464006a79fbc29cc05e7f252d27207d03b4 100644 (file)
@@ -5,7 +5,7 @@
 ###############################################################################
 
 Name: dnsmasq
-Version: 2.6
+Version: 2.7
 Release: 1
 Copyright: GPL
 Group: Productivity/Networking/DNS/Servers
index 8e5afd1a2da7418353f5515c954b9df7bb8984c5..92d0dd14de28b1998ce9f09a839ccbd630b11262 100644 (file)
--- a/dnsmasq.8
+++ b/dnsmasq.8
@@ -283,7 +283,7 @@ addresses given via
 .B dhcp-host
 or from /etc/ethers will be served.
 .TP
-.B \-G, --dhcp-host=[[<hwaddr>]|[id:<client_id>]][net:<netid>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
+.B \-G, --dhcp-host=[[<hwaddr>]|[id:[<client_id>][*]]][net:<netid>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
 Specify per host parameters for the DHCP server. This allows a machine
 with a particular hardware address to be always allocated the same
 hostname, IP address and lease time. A hostname specified like this
@@ -305,7 +305,10 @@ hardware addresses to identify hosts by prefixing with 'id:'. Thus:
 .B --dhcp-host=id:01:02:03:04,..... 
 refers to the host with client identifier 01:02:03:04. It is also
 allowed to specify the client ID as text, like this:
-.B --dhcp-host=id:clientidastext,.....
+.B --dhcp-host=id:clientidastext,..... 
+The special option id:* means "ignore any client-id 
+and use MAC addresses only." This is useful when a client presents a client-id sometimes 
+but not others.
 If a name appears in /etc/hosts, the associated address can be
 allocated to a DHCP lease, but only if a 
 .B --dhcp-host
@@ -340,7 +343,7 @@ specfied in RFC2132. For example, to set the default route option to
 192.168.4.4, do 
 .B --dhcp-option=3,192.168.4.4
 and to set the time-server address to 192.168.0.4, do
-.B dhcp-option=42,192.168.0.4
+.B --dhcp-option=42,192.168.0.4
 The special address 0.0.0.0 is taken to mean "the address of the
 machine running dnsmasq". Data types allowed are comma seperated
 dotted-quad IP addresses, a decimal number, colon-seperated hex digits
@@ -353,6 +356,15 @@ possible to generate the correct data type; it is quite possible to
 persuade dnsmasq to generate illegal DHCP packets with injudicious use
 of this flag.
 .TP
+.B \-U, --dhcp-vendorclass=<network-id>,<vendor-class>
+Map from a vendor-class string to a network id. Most DHCP clients provide a 
+"vendor class" which represents, in some sense, the type of host. This options 
+maps vendor classes to network ids, so that DHCP options may be selectively delivered
+to different classes of hosts. For example 
+.B dhcp-vendorclass=printers,Hewlett-Packard JetDirect
+will allow options to be set only for HP printers like so:
+.B --dhcp-option=printers,3,192.168.4.4
+.TP
 .B \-M, --dhcp-boot=<filename>,[<servername>[,<server address>]]
 Set BOOTP options to be returned by the DHCP server. These are needed
 for machines which network boot, and tell the machine where to collect
index ce3bcde3567b298fdbee26d5accffb93e5c3ad66..f4d59698a862b6f6859c4f27f91f127463913efc 100644 (file)
@@ -161,6 +161,12 @@ filterwin2k
 # address is 11:22:33:44:55:66
 #dhcp-host=11:22:33:44:55:66,ignore
 
+# Ignore any client-id presented by the machine with ethernet
+# address 11:22:33:44:55:66. This is useful to prevent a machine 
+# being treated differently when running under different OS's or
+# between PXE boot and OS boot.
+#dhcp-host=11:22:33:44:55:66,id:*
+
 # Send extra options which are tagged as "red" to 
 # the machine with ethernet address 11:22:33:44:55:66
 #dhcp-host=11:22:33:44:55:66,net:red
index ad9e08de4b9a88ebd4d4b157c479502dc24eeaaf..b6bf7465e557e259130b3fb5043767fd97e4aa51 100644 (file)
@@ -12,7 +12,7 @@
 
 /* Author's email: simon@thekelleys.org.uk */
 
-#define VERSION "2.6"
+#define VERSION "2.7"
 
 #define FTABSIZ 150 /* max number of outstanding requests */
 #define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
index 02e42b9357d014171ac2c766a0ec9a3a5cd2eb98..5c6f7470a6ac9d181225420f95139853ce90759b 100644 (file)
@@ -60,7 +60,8 @@ void dhcp_init(int *fdp, int* rfdp)
 }
 
 void dhcp_packet(struct dhcp_context *contexts, char *packet, 
-                struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs, 
+                struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs,
+                struct dhcp_vendor *vendors,
                 time_t now, char *namebuff, char *domain_suffix,
                 char *dhcp_file, char *dhcp_sname, 
                 struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
@@ -181,7 +182,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
        /* we can use the interface netmask if either the packet came direct,
          or it came via a relay listening on the same network. This sounds unlikely,
          but it happens with win4lin. */
-       if ((source.s_addr & iface_netmask.s_addr) != (iface_addr.s_addr & iface_netmask.s_addr))
+       if (!is_same_net(source, iface_addr, iface_netmask))
         iface_netmask.s_addr = 0;
        else if (ioctl(dhcp_fd, SIOCGIFBRDADDR, &ifr) != -1)
         iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
@@ -193,8 +194,8 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
       struct in_addr netmask = context->netmask.s_addr ? context->netmask : iface_netmask;
 
       if (netmask.s_addr && 
-         (source.s_addr & netmask.s_addr) == (context->start.s_addr & netmask.s_addr) &&
-         (source.s_addr & netmask.s_addr) == (context->end.s_addr & netmask.s_addr))
+         is_same_net(source, context->start, netmask) &&
+         is_same_net(source, context->end, netmask))
        break;
     }
       
@@ -225,7 +226,7 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
      DHCP broadcast, either this machine or a relay. In the special case that the relay
      is on the same network as us, we set the default route to us, not the relay.
      This is the win4lin scenario again. */ 
-  if ((source.s_addr & context->netmask.s_addr) == (iface_addr.s_addr & context->netmask.s_addr))
+  if (is_same_net(source, iface_addr, context->netmask))
     router = iface_addr;
   else
     router = source;
@@ -233,8 +234,8 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
   lease_prune(NULL, now); /* lose any expired leases */
   newlen = dhcp_reply(context, iface_addr, ifr.ifr_name, ifr.ifr_mtu, 
                      rawpacket, sz, now, namebuff, 
-                     dhcp_opts, dhcp_configs, domain_suffix, dhcp_file,
-                     dhcp_sname, dhcp_next_server, router);
+                     dhcp_opts, dhcp_configs, vendors, domain_suffix, 
+                     dhcp_file, dhcp_sname, dhcp_next_server, router);
   lease_update_file(0, now);
   lease_update_dns();
          
@@ -350,7 +351,6 @@ void dhcp_packet(struct dhcp_context *contexts, char *packet,
     }
 }
 
-         
 int address_available(struct dhcp_context *context, struct in_addr taddr)
 {
   /* Check is an address is OK for this network, ie
@@ -379,38 +379,47 @@ int address_available(struct dhcp_context *context, struct in_addr taddr)
 }
 
 int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
-                    struct in_addr *addrp)   
+                    struct in_addr *addrp, unsigned char *hwaddr)   
 {
   /* Find a free address: exlude anything in use and anything allocated to
      a particular hwaddr/clientid/hostname in our configuration */
 
   struct dhcp_config *config;
-  struct in_addr start = context->last;
+  struct in_addr start, addr ;
+  int i, j;
 
   /* start == end means no dynamic leases. */
   if (context->end.s_addr == context->start.s_addr)
     return 0;
-
+  
+  /* pick a seed based on hwaddr then iterate until we find a free address. */
+  for (j = 0, i = 0; i < ETHER_ADDR_LEN; i++)
+    j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
+  
+  start.s_addr = addr.s_addr = 
+    htonl(ntohl(context->start.s_addr) + 
+         (j % (ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
   do {
-    if (context->last.s_addr == context->end.s_addr)
-      context->last = context->start;
+    if (addr.s_addr == context->end.s_addr)
+      addr = context->start;
     else
-      context->last.s_addr = htonl(ntohl(context->last.s_addr) + 1);
+      addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
 
     
-    if (!lease_find_by_addr(context->last))
+    if (!lease_find_by_addr(addr))
       {
        for (config = configs; config; config = config->next)
-         if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == context->last.s_addr)
+         if ((config->flags & CONFIG_ADDR) && config->addr.s_addr == addr.s_addr)
            break;
        
        if (!config)
          {
-           *addrp = context->last;
+           *addrp = addr;
            return 1;
          }
       }
-  } while (context->last.s_addr != start.s_addr);
+  } while (addr.s_addr != start.s_addr);
   
   return 0;
 }
@@ -421,7 +430,7 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *
     return 1;
   if (!(config->flags & CONFIG_ADDR))
     return 1;
-  if ((config->addr.s_addr & context->netmask.s_addr) == (context->start.s_addr & context->netmask.s_addr))
+  if (is_same_net(config->addr, context->start, context->netmask))
     return 1;
   
   return 0;
index 3169e55c4c64e48bc1ad7d26932e8151861fb023..fff2ff7c8bd5e398def1230692bd069854b123d0 100644 (file)
@@ -66,6 +66,7 @@ int main (int argc, char **argv)
   struct dhcp_context *dhcp_tmp, *dhcp = NULL;
   struct dhcp_config *dhcp_configs = NULL;
   struct dhcp_opt *dhcp_options = NULL;
+  struct dhcp_vendor *dhcp_vendors = NULL;
   char *dhcp_file = NULL, *dhcp_sname = NULL;
   struct in_addr dhcp_next_server;
   int leasefd = -1, dhcpfd = -1, dhcp_raw_fd = -1;
@@ -109,16 +110,10 @@ int main (int argc, char **argv)
                      &username, &groupname, &domain_suffix, &runfile, 
                      &if_names, &if_addrs, &if_except, &bogus_addr, 
                      &serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
-                     &dhcp, &dhcp_configs, &dhcp_options,
+                     &dhcp, &dhcp_configs, &dhcp_options, &dhcp_vendors,
                      &dhcp_file, &dhcp_sname, &dhcp_next_server, &maxleases, &min_leasetime,
                      &doctors);
 
-  /* if we cannot support binding the wildcard address, set the "bind only
-     interfaces in use" option */
-#ifndef  HAVE_UDP_SRC_DST
-  options |= OPT_NOWILD;
-#endif
-
   if (!lease_file)
     {
       if (dhcp)
@@ -129,7 +124,13 @@ int main (int argc, char **argv)
     die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
 #endif
   
-  interfaces = enumerate_interfaces(if_names, if_addrs, if_except, port);
+#ifndef  HAVE_UDP_SRC_DST
+  /* if we cannot support binding the wildcard address, set the "bind only
+     interfaces in use" option */
+  options |= OPT_NOWILD;
+#endif
+
+  interfaces = enumerate_interfaces(&if_names, &if_addrs, if_except, port);
   if (options & OPT_NOWILD)
     listeners = create_bound_listeners(interfaces);
   else
@@ -397,7 +398,7 @@ int main (int argc, char **argv)
                                    dnamebuff, last_server, bogus_addr, doctors);
 
       if (dhcp && FD_ISSET(dhcpfd, &rset))
-       dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs,
+       dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs, dhcp_vendors,
                    now, dnamebuff, domain_suffix, dhcp_file,
                    dhcp_sname, dhcp_next_server, dhcpfd, dhcp_raw_fd,
                    if_names, if_addrs, if_except);
index edb10ad4b83e16d363b8b3ccaa256a6f6f40196b..0021d4e0a0137f49662049ad01355e727536dd69 100644 (file)
@@ -130,7 +130,7 @@ struct crec {
 };
 
 #define F_IMMORTAL  1
-#define F_CONFIG    2
+#define F_CONFIG   2
 #define F_REVERSE   4
 #define F_FORWARD   8
 #define F_DHCP      16 
@@ -255,18 +255,25 @@ struct dhcp_config {
 #define CONFIG_NAME     16
 #define CONFIG_ADDR     32
 #define CONFIG_NETID    64
+#define CONFIG_NOCLID  128
 
 struct dhcp_opt {
   int opt, len, is_addr;
   unsigned char *val;
   char *netid;
   struct dhcp_opt *next;
- };
+};
+
+struct dhcp_vendor {
+  int len;
+  char *data, *net;
+  struct dhcp_vendor *next;
+};
 
 struct dhcp_context {
   unsigned int lease_time;
   struct in_addr netmask, broadcast;
-  struct in_addr start, end, last; /* range of available addresses */
+  struct in_addr start, end; /* range of available addresses */
   char *netid;
   struct dhcp_context *next;
 };
@@ -341,6 +348,8 @@ int sa_len(union mysockaddr *addr);
 int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
 int hostname_isequal(unsigned char *a, unsigned char *b);
 time_t dnsmasq_time(int fd);
+int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
+
 /* option.c */
 unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resolv_file, 
                       char **mxname, char **mxtarget, char **lease_file, 
@@ -349,7 +358,8 @@ unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resol
                       struct iname **if_names, struct iname **if_addrs, struct iname **if_except, 
                       struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize, 
                       int *port, int *query_port, unsigned long *local_ttl, char **addn_hosts,
-                      struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf, struct dhcp_opt **opts,
+                      struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf, 
+                      struct dhcp_opt **opts, struct dhcp_vendor **dhcp_vendors,
                       char **dhcp_file, char **dhcp_sname, struct in_addr *dhcp_next_server,
                       int *maxleases, unsigned int *min_leasetime, struct doctor **doctors);
 
@@ -367,8 +377,8 @@ struct server *receive_query(struct listener *listen, char *packet, char *mxname
 /* network.c */
 struct server *reload_servers(char *fname, char *buff, struct server *servers, int query_port);
 struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds);
-struct irec *enumerate_interfaces(struct iname *names,
-                                 struct iname *addrs,
+struct irec *enumerate_interfaces(struct iname **names,
+                                 struct iname **addrs,
                                  struct iname *except,
                                  int port);
 struct listener *create_wildcard_listeners(int port);
@@ -377,13 +387,14 @@ struct listener *create_bound_listeners(struct irec *interfaces);
 void dhcp_init(int *fdp, int* rfdp);
 void dhcp_packet(struct dhcp_context *contexts, char *packet, 
                 struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs, 
+                struct dhcp_vendor *vendors,
                 time_t now, char *namebuff, char *domain_suffix,
                 char *dhcp_file, char *dhcp_sname, 
                 struct in_addr dhcp_next_server, int dhcp_fd, int raw_fd,
                 struct iname *names, struct iname *addrs, struct iname *except);
 int address_available(struct dhcp_context *context, struct in_addr addr);
 int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
-                    struct in_addr *addrp);
+                    struct in_addr *addrp, unsigned char *hwaddr);
 struct dhcp_config *find_config(struct dhcp_config *configs,
                                struct dhcp_context *context,
                                unsigned char *clid, int clid_len,
@@ -391,6 +402,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);
+
 /* lease.c */
 void lease_update_file(int force, time_t now);
 void lease_update_dns(void);
@@ -404,6 +416,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len);
 struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
 void lease_prune(struct dhcp_lease *target, time_t now);
 void lease_update_from_configs(struct dhcp_config *dhcp_configs, char *domain);
+
 /* rfc2131.c */
 int dhcp_reply(struct dhcp_context *context, 
               struct in_addr iface_addr,
@@ -412,6 +425,7 @@ int dhcp_reply(struct dhcp_context *context,
               struct udp_dhcp_packet *rawpacket,
               unsigned int sz, time_t now, char *namebuff, 
               struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs, 
+              struct dhcp_vendor *vendors,
               char *domain_suffix, char *dhcp_file, char *dhcp_sname, 
               struct in_addr dhcp_next_server, struct in_addr router);
 
index 54edf9d6f6188bb1d0e8d715c2d25e9b21085c3e..e2f0f83f6c37c2405c3233d8e2734852b1805c42 100644 (file)
@@ -25,7 +25,7 @@ static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *a
   if (except)
     for (tmp = except; tmp; tmp = tmp->next)
       if (tmp->name && strcmp(tmp->name, name) == 0)
-       return NULL;
+       return list;
   
   /* we may need to check the whitelist */
   if (names || addrs)
@@ -38,31 +38,31 @@ static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *a
          if (sockaddr_isequal(&tmp->addr, addr))
            break;
       if (!tmp) 
-       return NULL;
+       return list;
     }
   
   /* check whether the interface IP has been added already 
      it is possible to have multiple interfaces with the same address */
-  for (; list; list = list->next) 
-    if (sockaddr_isequal(&list->addr, addr))
+  for (iface = list; iface; iface = iface->next) 
+    if (sockaddr_isequal(&iface->addr, addr))
       break;
-  if (list)
-    return NULL;
+  if (iface)
+    return list;
   
   /* If OK, add it to the head of the list */
   iface = safe_malloc(sizeof(struct irec));
   iface->addr = *addr;
-
+  iface->next = list;
   return iface;
 }
 
 
-struct irec *enumerate_interfaces(struct iname *names,
-                                 struct iname *addrs,
+struct irec *enumerate_interfaces(struct iname **names,
+                                 struct iname **addrs,
                                  struct iname *except,
                                  int port)
 {
-  struct irec *iface = NULL, *new;
+  struct irec *iface = NULL;
   char *buf, *ptr;
   struct ifreq *ifr = NULL;
   struct ifconf ifc;
@@ -137,22 +137,19 @@ struct irec *enumerate_interfaces(struct iname *names,
        die("ioctl error getting interface flags: %m", NULL);
 
       /* If we are restricting the set of interfaces to use, make
-        sure that loopback interfaces are in that set. */
-      if (names && (ifr->ifr_flags & IFF_LOOPBACK))
+        sure that loopback interfaces are in that set. Note that
+        this is done as addresses rather than interface names so
+        as not to confuse the no-IPRECVIF workaround on the DHCP code */
+      if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
        {
          struct iname *lo = safe_malloc(sizeof(struct iname));
-         lo->name = safe_string_alloc(ifr->ifr_name);
-         lo->next = names->next;
-         names->next = lo;
-       }
-
-      if ((new = add_iface(iface, ifr->ifr_name, 
-                          &addr, names, addrs, except)))
-       {
-         new->next = iface;
-         iface = new;
+         lo->addr = addr;
+         lo->next = *addrs;
+         *addrs = lo;
        }
 
+      iface = add_iface(iface, ifr->ifr_name, &addr, *names, *addrs, except);
+       
 #if defined(HAVE_LINUX_IPV6_PROC) && defined(HAVE_IPV6)
       /* IPv6 addresses don't seem to work with SIOCGIFCONF. Barf */
       /* This code snarfed from net-tools 1.60 and certainly linux specific, though
@@ -194,11 +191,17 @@ struct irec *enumerate_interfaces(struct iname *names,
            fclose(f);
          }
        
-       if (found && (new = add_iface(iface, ifr->ifr_name,
-                                     &addr6, names, addrs, except)))
+       if (found)
          {
-           new->next = iface;
-           iface = new;
+           if (*names && (ifr->ifr_flags & IFF_LOOPBACK))
+             {
+               struct iname *lo = safe_malloc(sizeof(struct iname));
+               lo->addr = addr6;
+               lo->next = *addrs;
+               *addrs = lo;
+             }
+           
+           iface = add_iface(iface, ifr->ifr_name, &addr6, *names, *addrs, except);
          }
       }
 #endif /* LINUX */
index 2aab2349ccfa89587169df12a710c4bef88faab0..b1fef2fb9fec3603995447ccf7983a6f5ee171cc 100644 (file)
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000 - 2003 Simon Kelley
+/* dnsmasq is Copyright (c) 2000 - 2004 Simon Kelley
 
    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
@@ -21,7 +21,7 @@ struct myoption {
   int val;
 };
 
-#define OPTSTRING "ZDNLERzowefnbvhdqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:"
+#define OPTSTRING "ZDNLERzowefnbvhdqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:"
 
 static struct myoption opts[] = { 
   {"version", 0, 0, 'v'},
@@ -70,6 +70,7 @@ static struct myoption opts[] = {
   {"bind-interfaces", 0, 0, 'z'},
   {"read-ethers", 0, 0, 'Z' },
   {"alias", 1, 0, 'V' },
+  {"dhcp-vendorclass", 1, 0, 'U'},
   {0, 0, 0, 0}
 };
 
@@ -139,6 +140,7 @@ static char *usage =
 "-t, --mx-target=host_name           Specify the host in an MX reply.\n"
 "-T, --local-ttl=time                Specify time-to-live in seconds for replies from /etc/hosts.\n"
 "-u, --user=username                 Change to this user after startup. (defaults to " CHUSER ").\n" 
+"-U, --dhcp-vendorclass=<id>,<class> Map DHCP vendor class to option set.\n"
 "-v, --version                       Display dnsmasq version.\n"
 "-V, --alias=addr,addr,mask          Translate IPv4 addresses from upstream servers.\n"
 "-w, --help                          Display this message.\n"
@@ -155,7 +157,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
                        struct iname **if_names, struct iname **if_addrs, struct iname **if_except,
                        struct bogus_addr **bogus_addr, struct server **serv_addrs, int *cachesize, int *port, 
                        int *query_port, unsigned long *local_ttl, char **addn_hosts, struct dhcp_context **dhcp,
-                       struct dhcp_config **dhcp_conf, struct dhcp_opt **dhcp_opts, char **dhcp_file,
+                       struct dhcp_config **dhcp_conf, struct dhcp_opt **dhcp_opts, struct dhcp_vendor **dhcp_vendors, char **dhcp_file,
                        char **dhcp_sname, struct in_addr *dhcp_next_server, int *dhcp_max, 
                        unsigned int *min_leasetime, struct doctor **doctors)
 {
@@ -726,7 +728,6 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
                      }
                  }
                                
-               new->last = new->start;
                if (new->lease_time < *min_leasetime)
                  *min_leasetime = new->lease_time;
                break;
@@ -760,40 +761,45 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
                          (arg[1] == 'd' || arg[1] == 'D') &&
                          arg[2] == ':')
                        {
-                         int len;
-                         arg += 3; /* dump id: */
-                         if (strchr(arg, ':'))
+                         if (arg[3] == '*')
+                           new->flags |= CONFIG_NOCLID;
+                         else
                            {
-                             /* decode hex in place */
-                             char *p = arg, *q = arg, *r;
-                             while (*p)
+                             int len;
+                             arg += 3; /* dump id: */
+                             if (strchr(arg, ':'))
                                {
-                                 for (r = p; *r && *r != ':'; r++);
-                                 if (*r)
+                                 /* decode hex in place */
+                                 char *p = arg, *q = arg, *r;
+                                 while (*p)
                                    {
-                                     if (r != p)
+                                     for (r = p; *r && *r != ':'; r++);
+                                     if (*r)
                                        {
-                                         *r = 0;
-                                         *(q++) = strtol(p, NULL, 16);
+                                         if (r != p)
+                                           {
+                                             *r = 0;
+                                             *(q++) = strtol(p, NULL, 16);
+                                           }
+                                         p = r+1;
+                                       }
+                                     else
+                                       {
+                                         if (*p)
+                                           *(q++) = strtol(p, NULL, 16);
+                                         break;
                                        }
-                                     p = r+1;
-                                   }
-                                 else
-                                   {
-                                     if (*p)
-                                       *(q++) = strtol(p, NULL, 16);
-                                     break;
                                    }
+                                 len = q - arg;
                                }
-                             len = q - arg;
+                             else
+                               len = strlen(arg);
+                             
+                             new->flags |= CONFIG_CLID;
+                             new->clid_len = len;
+                             new->clid = safe_malloc(len);
+                             memcpy(new->clid, arg, len);
                            }
-                         else
-                           len = strlen(arg);
-                         
-                         new->flags |= CONFIG_CLID;
-                         new->clid_len = len;
-                         new->clid = safe_malloc(len);
-                         memcpy(new->clid, arg, len);
                        }
                      else if ((arg[0] == 'n' || arg[0] == 'N') &&
                               (arg[1] == 'e' || arg[1] == 'E') &&
@@ -1057,6 +1063,26 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
                break;
              }
 
+           case 'U':
+             {
+               char *comma;
+               
+               if (!(comma = strchr(optarg, ',')))
+                 option = '?';
+               else
+                 {
+                   struct dhcp_vendor *new = safe_malloc(sizeof(struct dhcp_vendor));
+                   *comma = 0;
+                   new->net = safe_string_alloc(optarg);
+                   new->len = strlen(comma+1);
+                   new->data = safe_malloc(new->len);
+                   memcpy(new->data, comma+1, new->len);
+                   new->next = *dhcp_vendors;
+                   *dhcp_vendors = new;
+                 }
+               break;
+             }
+                   
            case 'V':
              {
                char *a[3] = { NULL, NULL, NULL };
index 4b9d086bfce72ff97f6c38257fb9d63bc5b7d3d7..4f3df709394fa7cd36079a71926b02ba49c7f481 100644 (file)
@@ -443,7 +443,7 @@ void extract_neg_addrs(HEADER *header, unsigned int qlen, char *name, time_t now
 static void dns_doctor(struct doctor *doctor, struct in_addr *addr)
 {
   for (; doctor; doctor = doctor->next)
-    if ((doctor->in.s_addr & doctor->mask.s_addr) == (addr->s_addr & doctor->mask.s_addr))
+    if (is_same_net(doctor->in, *addr, doctor->mask))
       {
        addr->s_addr &= ~doctor->mask.s_addr;
        addr->s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
index 1b7364d02ed67ccb835d092dd5603348fee50445..dcba4b38457dc7ff5398b6fb2230a7af85e139e8 100644 (file)
@@ -35,6 +35,7 @@
 #define OPTION_MAXMESSAGE        57
 #define OPTION_T1                58
 #define OPTION_T2                59
+#define OPTION_VENDOR_ID         60
 #define OPTION_CLIENT_ID         61
 #define OPTION_END               255
 
@@ -77,6 +78,7 @@ int dhcp_reply(struct dhcp_context *context,
               struct udp_dhcp_packet *rawpacket,
               unsigned int sz, time_t now, char *namebuff, 
               struct dhcp_opt *dhcp_opts, struct dhcp_config *dhcp_configs, 
+              struct dhcp_vendor *vendors, 
               char *domain_suffix, char *dhcp_file, char *dhcp_sname, 
               struct in_addr dhcp_next_server, struct in_addr router)
 {
@@ -93,7 +95,9 @@ int dhcp_reply(struct dhcp_context *context,
   unsigned int renewal_time, expires_time, def_time;
   struct dhcp_config *config;
   char *netid;
-  
+  struct in_addr addr;
+  unsigned short fuzz = 0;
+
   if (mess->op != BOOTREQUEST || 
       mess->hlen != ETHER_ADDR_LEN ||
       mess->cookie != htonl(DHCP_COOKIE))
@@ -137,18 +141,7 @@ int dhcp_reply(struct dhcp_context *context,
       clid =  mess->chaddr;
       clid_len = 0;
     }
-  
-  /* do we have a lease in store? */
-  lease = lease_find_by_client(clid, clid_len);
-  
-  if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS)))
-    {
-      int len = option_len(opt);
-      req_options = namebuff;
-      memcpy(req_options, option_ptr(opt), len);
-      req_options[len] = OPTION_END;
-    }
-  
+    
   if ((config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, NULL)) && 
       have_config(config, CONFIG_NAME))
     hostname = config->hostname;
@@ -177,13 +170,34 @@ int dhcp_reply(struct dhcp_context *context,
              else
                *dot = 0; /* truncate */
            }
+         /* 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 */
-  config = find_config(dhcp_configs, context, clid, clid_len, mess->chaddr, hostname);
+  
   def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
-  netid = have_config(config, CONFIG_NETID) ? config->netid : context->netid;
+  
+  netid = context->netid;
+  if (have_config(config, CONFIG_NETID))
+    netid = config->netid;
+  else if ((opt = option_find(mess, sz, OPTION_VENDOR_ID)))
+    {
+      struct dhcp_vendor *vendor;
+      for (vendor = vendors; vendor; vendor = vendor->next)
+       if (vendor->len == option_len(opt) &&
+           memcmp(vendor->data, option_ptr(opt), vendor->len) == 0)
+         netid = vendor->net;
+    }
+  
+  /* Can have setting to ignore the client ID for a particular MAC address or hostname */
+  if (have_config(config, CONFIG_NOCLID))
+    {
+      clid =  mess->chaddr;
+      clid_len = 0;
+    }
+    
+  /* do we have a lease in store? */
+  lease = lease_find_by_client(clid, clid_len);
   
   if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
     {
@@ -203,11 +217,19 @@ int dhcp_reply(struct dhcp_context *context,
       else 
        expires_time = def_time;
     }
+  
+  if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS)))
+    {
+      int len = option_len(opt);
+      req_options = namebuff;
+      memcpy(req_options, option_ptr(opt), len);
+      req_options[len] = OPTION_END;
+    }
+  
   if (!(opt = option_find(mess, sz, OPTION_MESSAGE_TYPE)))
     return 0;
   
-  switch (opt[2])
+  switch (option_uint(opt, 1))
     {
     case DHCPDECLINE:
       if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER)) ||
@@ -261,39 +283,48 @@ int dhcp_reply(struct dhcp_context *context,
       
     case DHCPDISCOVER:
       if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))   
-       mess->yiaddr = option_addr(opt);
+       addr = option_addr(opt);
       
       if (have_config(config, CONFIG_DISABLE))
        message = "ignored";
       else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
        mess->yiaddr = config->addr;
-      else if (lease && 
-              ((lease->addr.s_addr & context->netmask.s_addr) == 
-               (context->start.s_addr & context->netmask.s_addr)))
+      else if (lease && is_same_net(lease->addr, context->start, context->netmask))
        mess->yiaddr = lease->addr;
-      else if ((!opt || !address_available(context, mess->yiaddr)) &&
-              !address_allocate(context, dhcp_configs, &mess->yiaddr))
+      else if (opt && address_available(context, addr))
+       mess->yiaddr = addr;
+      else if (!address_allocate(context, dhcp_configs, &mess->yiaddr, mess->chaddr))
        message = "no address available";
-        
-      log_packet("DISCOVER", opt ? &mess->yiaddr : NULL, mess->chaddr, iface_name, message);          
+      
+      log_packet("DISCOVER", opt ? &addr : NULL, mess->chaddr, iface_name, message);          
+      
       if (message)
        return 0;
-
+      
+      /* ensure that we send the reply by steam even if a buggy client sets this. */
+      mess->ciaddr.s_addr = 0;
       bootp_option_put(mess, dhcp_file, dhcp_sname);
-      mess->siaddr = dhcp_next_server;
+      mess->siaddr = dhcp_next_server.s_addr ? dhcp_next_server : iface_addr;
       p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
       p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
       p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time);
+      /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
+      if (expires_time != 0xffffffff)
+       {
+         p = option_put(p, end, OPTION_T1, 4, (expires_time/2));
+         p = option_put(p, end, OPTION_T2, 4, ((expires_time * 7)/8));
+       }
       p = do_req_options(context, p, end, req_options, dhcp_opts, domain_suffix, 
                         NULL, router, iface_addr, iface_mtu, netid);
       p = option_put(p, end, OPTION_END, 0, 0);
       
       log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL);
       return p - (unsigned char *)mess;
-
       
     case DHCPREQUEST:
-      if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
+      if (have_config(config, CONFIG_DISABLE))
+       message = "disabled";
+      else if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
        {
          /* SELECTING  or INIT_REBOOT */
          mess->yiaddr = option_addr(opt);
@@ -333,15 +364,17 @@ int dhcp_reply(struct dhcp_context *context,
          mess->yiaddr = mess->ciaddr;
          if (!lease || mess->ciaddr.s_addr != lease->addr.s_addr)
            message = "lease not found";
+         
+         /* desynchronise renewals */
+         fuzz = rand16();
+         while (fuzz > (renewal_time/16))
+           fuzz = fuzz/2;
        }
       
       /* If a machine moves networks whilst it has a lease, we catch that here. */
-      if ((mess->yiaddr.s_addr & context->netmask.s_addr) != (context->start.s_addr & context->netmask.s_addr))
+      if (!message && !is_same_net(mess->yiaddr, context->start, context->netmask))
        message = "wrong network";
       
-      if (have_config(config, CONFIG_DISABLE))
-       message = "disabled";
-
       log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
       
       if (message)
@@ -364,15 +397,12 @@ int dhcp_reply(struct dhcp_context *context,
       lease_set_expires(lease, renewal_time == 0xffffffff ? 0 : now + (time_t)renewal_time);
       
       bootp_option_put(mess, dhcp_file, dhcp_sname);
-      mess->siaddr = dhcp_next_server;
+      mess->siaddr = dhcp_next_server.s_addr ? dhcp_next_server : iface_addr;
       p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
       p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
       p = option_put(p, end, OPTION_LEASE_TIME, 4, renewal_time);
       if (renewal_time != 0xffffffff)
        {
-         unsigned short fuzz = rand16();
-         while (fuzz > (renewal_time/16))
-           fuzz = fuzz/2;
          p = option_put(p, end, OPTION_T1, 4, (renewal_time/2) - fuzz);
          p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz);
        }
@@ -383,12 +413,12 @@ int dhcp_reply(struct dhcp_context *context,
       
     case DHCPINFORM:
       if (have_config(config, CONFIG_DISABLE))
-       {
-         log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, "ignored");
-         return 0;
-       }
+       message = "ignored";
       
-      log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, NULL);
+      log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, message);
+     
+      if (message || mess->ciaddr.s_addr == 0)
+       return 0;
       
       p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
       p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
@@ -546,6 +576,10 @@ static int in_list(unsigned char *list, int opt)
 {
   int i;
   
+  /* If no requested options, send everything, not nothing. */
+  if (!list)
+    return 1;
+  
   for (i = 0; list[i] != OPTION_END; i++)
     if (opt == list[i])
       return 1;
@@ -555,11 +589,15 @@ static int in_list(unsigned char *list, int opt)
 
 static struct dhcp_opt *option_find2(char *netid, struct dhcp_opt *opts, int opt)
 {
-  for (; opts; opts = opts->next)
-    if (opts->opt == opt && 
-       (!opts->netid || (netid && strcmp(opts->netid, netid) == 0)))
-      return opts;
-  return NULL;
+  struct dhcp_opt *tmp;
+  
+  for (tmp = opts; tmp; tmp = tmp->next)
+    if (tmp->opt == opt && 
+       ((!netid && !tmp->netid) || 
+        (netid && tmp->netid && strcmp(tmp->netid, netid) == 0)))
+      return tmp;
+
+  return netid ? option_find2(NULL, opts, opt) : NULL;
 }
 
 static unsigned char *do_req_options(struct dhcp_context *context,
@@ -571,11 +609,8 @@ static unsigned char *do_req_options(struct dhcp_context *context,
                                     struct in_addr iface_addr,
                                     int iface_mtu, char *netid)
 {
-  int i;
-  
-  if (!req_options)
-    return p;
-  
+  struct dhcp_opt *opt;
+    
   if (in_list(req_options, OPTION_MAXMESSAGE))
     p = option_put(p, end, OPTION_MAXMESSAGE, 2, 
                   DNSMASQ_PACKETSZ > iface_mtu ? 
@@ -607,14 +642,13 @@ static unsigned char *do_req_options(struct dhcp_context *context,
   if (hostname && in_list(req_options, OPTION_HOSTNAME))
     p = option_put_string(p, end, OPTION_HOSTNAME, hostname);
   
-  for (i = 0; req_options[i] != OPTION_END; i++)
+  for (opt=config_opts; opt; opt = opt->next)
     {
-      struct dhcp_opt *opt;
-     
-      if (req_options[i] == OPTION_HOSTNAME || 
-         req_options[i] == OPTION_MAXMESSAGE ||
-         !(opt = option_find2(netid, config_opts, req_options[i])) || 
-         (p + opt->len + 3 >= end))
+      if (opt->opt == OPTION_HOSTNAME ||
+         opt->opt == OPTION_MAXMESSAGE ||
+         !in_list(req_options, opt->opt) ||
+         opt != option_find2(netid, config_opts, opt->opt) ||
+         p + opt->len + 3 >= end)
        continue;
       
       /* For the options we have default values on
@@ -631,7 +665,7 @@ static unsigned char *do_req_options(struct dhcp_context *context,
       *(p++) = opt->len;
       if (opt->len == 0)
        continue;
-       
+      
       if (opt->is_addr)
        {
          int j;
index 3c682329064b6c9dc38fb390779f41c28a8a5120..a6b5bfe45533eee02df973fd7062d592418c162e 100644 (file)
@@ -228,3 +228,8 @@ time_t dnsmasq_time(int fd)
   return time(NULL);
 #endif
 }
+
+int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
+{
+  return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
+}