]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/commitdiff
dhcp: Update to 4.2.2.
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 28 Aug 2012 18:19:35 +0000 (20:19 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 17 Sep 2012 19:41:05 +0000 (21:41 +0200)
34 files changed:
config/rootfiles/common/dhcp
lfs/dhcp
make.sh
src/patches/dhcp-4.2.0-PPP.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-UseMulticast.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-add_timeout_when_NULL.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-default-requested-options.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-dhclient-decline-backoff.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-errwarn-message.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-garbage-chars.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-honor-expired.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-inherit-leases.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-logpid.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-missing-ipv6-not-fatal.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-noprefixavail.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-paths.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-release-by-ifup.patch [new file with mode: 0644]
src/patches/dhcp-4.2.0-unicast-bootp.patch [new file with mode: 0644]
src/patches/dhcp-4.2.1-64_bit_lease_parse.patch [new file with mode: 0644]
src/patches/dhcp-4.2.1-invalid-dhclient-conf.patch [new file with mode: 0644]
src/patches/dhcp-4.2.1-manpages.patch [new file with mode: 0644]
src/patches/dhcp-4.2.1-retransmission.patch [new file with mode: 0644]
src/patches/dhcp-4.2.1-sendDecline.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-CLOEXEC.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-capability.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-dhclient-usage.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-gpxe-cid.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-improved-xid.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-lpf-ib.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-options.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-remove-bind.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-rfc3442-classless-static-routes.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-sharedlib.patch [new file with mode: 0644]
src/patches/dhcp-4.2.2-xen-checksum.patch [new file with mode: 0644]

index a165ca81a784858e921e723c1a1589e5b6593770..c2f5aed0557230addc606acb68dc87f82859ee69 100644 (file)
@@ -1,38 +1,39 @@
+#etc/dhclient.conf
 etc/dhcpd.conf
-#sbin/dhclient
-#sbin/dhclient-script
 #usr/bin/omshell
-#usr/include/dhcpctl.h
+#usr/include/dhcpctl
+#usr/include/dhcpctl/dhcpctl.h
 #usr/include/isc-dhcp
-#usr/include/isc-dhcp/boolean.h
 #usr/include/isc-dhcp/dst.h
-#usr/include/isc-dhcp/int.h
-#usr/include/isc-dhcp/lang.h
-#usr/include/isc-dhcp/list.h
-#usr/include/isc-dhcp/result.h
-#usr/include/isc-dhcp/types.h
 #usr/include/omapip
 #usr/include/omapip/alloc.h
 #usr/include/omapip/buffer.h
+#usr/include/omapip/convert.h
+#usr/include/omapip/hash.h
+#usr/include/omapip/isclib.h
 #usr/include/omapip/omapip.h
+#usr/include/omapip/omapip_p.h
+#usr/include/omapip/result.h
+#usr/include/omapip/trace.h
 #usr/lib/libdhcpctl.a
+#usr/lib/libdst.a
 #usr/lib/libomapi.a
-#usr/man/man1/omshell.1
-#usr/man/man3/dhcpctl.3
-#usr/man/man3/omapi.3
-#usr/man/man3/omshell.3
-#usr/man/man5/dhclient.conf.5
-#usr/man/man5/dhclient.leases.5
-#usr/man/man5/dhcp-eval.5
-#usr/man/man5/dhcp-options.5
-#usr/man/man5/dhcpd.conf.5
-#usr/man/man5/dhcpd.leases.5
-#usr/man/man8/dhclient-script.8
-#usr/man/man8/dhclient.8
-#usr/man/man8/dhcpd.8
-#usr/man/man8/dhcrelay.8
+#usr/sbin/dhclient
 usr/sbin/dhcpd
 #usr/sbin/dhcrelay
+#usr/share/man/man1/omshell.1
+#usr/share/man/man3/dhcpctl.3
+#usr/share/man/man3/omapi.3
+#usr/share/man/man5/dhclient.conf.5
+#usr/share/man/man5/dhclient.leases.5
+#usr/share/man/man5/dhcp-eval.5
+#usr/share/man/man5/dhcp-options.5
+#usr/share/man/man5/dhcpd.conf.5
+#usr/share/man/man5/dhcpd.leases.5
+#usr/share/man/man8/dhclient-script.8
+#usr/share/man/man8/dhclient.8
+#usr/share/man/man8/dhcpd.8
+#usr/share/man/man8/dhcrelay.8
 #var/state
 #var/state/dhcp
 var/state/dhcp/dhcpd.leases
index 845813cc8068ae145fc027bf9950f5d51e8f9d73..fa26b5cfb7143d04f8b0e5d0149d3fdebe8fcc2d 100644 (file)
--- a/lfs/dhcp
+++ b/lfs/dhcp
@@ -24,7 +24,7 @@
 
 include Config
 
-VER        = 3.1-ESV-R3
+VER        = 4.2.2
 
 THISAPP    = dhcp-$(VER)
 DL_FILE    = $(THISAPP).tar.gz
@@ -40,7 +40,7 @@ objects = $(DL_FILE)
 
 $(DL_FILE) = $(DL_FROM)/$(DL_FILE)
 
-$(DL_FILE)_MD5 = af3d8db60f62664f1d5538b81e406459
+$(DL_FILE)_MD5 = bb0f0434cd796f76aa7cead391d71f31
 
 install : $(TARGET)
 
@@ -70,10 +70,59 @@ $(subst %,%_MD5,$(objects)) :
 $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
        @$(PREBUILD)
        @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
-       cd $(DIR_APP) && ./configure
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-remove-bind.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-errwarn-message.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-options.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-release-by-ifup.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-dhclient-decline-backoff.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-unicast-bootp.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-dhclient-usage.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-default-requested-options.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-xen-checksum.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-manpages.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-paths.patch
+       # Has to be enabled after glibc update.
+       #cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-CLOEXEC.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-inherit-leases.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-garbage-chars.patch
+       #cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-missing-ipv6-not-fatal.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-add_timeout_when_NULL.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-64_bit_lease_parse.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-capability.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-logpid.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-UseMulticast.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-sendDecline.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-retransmission.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-rfc3442-classless-static-routes.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-honor-expired.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-noprefixavail.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-sharedlib.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-PPP.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-lpf-ib.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-improved-xid.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-gpxe-cid.patch
+       cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-invalid-dhclient-conf.patch
+
+       # Remove bundled BIND stuff.
+       # (requires newer autoconf)
+       #rm -rfv $(DIR_APP)/bind/bind.tar.gz
+       #cd $(DIR_APP) && autoreconf --verbose --force --install
+
+       cd $(DIR_APP) && \
+               ./configure \
+                       --prefix=/usr \
+                       --sysconfdir=/etc \
+                       --with-srv-lease-file=/var/state/dhcp/dhcpd.leases \
+                       --disable-static \
+                       --enable-paranoia \
+                       --enable-early-chroot \
+                       --disable-dhcpv6
        cd $(DIR_APP) && make $(MAKETUNING)
-       cd $(DIR_APP) && make LIBDIR=/usr/lib INCDIR=/usr/include install
+       cd $(DIR_APP) && make install
+
+       mkdir -pv /var/state/dhcp
        touch /var/state/dhcp/dhcpd.leases
+
        ln -sf $(CONFIG_ROOT)/dhcp/dhcpd.conf /etc/dhcpd.conf
        @rm -rf $(DIR_APP)
        @$(POSTBUILD)
diff --git a/make.sh b/make.sh
index c30786da466aeb0f5326a27efbfce8dc083d84c2..cd77ce031ad809fb78fec171cc867b2b57f7cf60 100755 (executable)
--- a/make.sh
+++ b/make.sh
@@ -373,6 +373,7 @@ buildipfire() {
   export LOGFILE
   ipfiremake configroot
   ipfiremake backup
+  ipfiremake bind
   ipfiremake dhcp
   ipfiremake dhcpcd
   ipfiremake libusb
@@ -513,7 +514,6 @@ buildipfire() {
   ipfiremake apache2                   PASS=C
   ipfiremake arping
   ipfiremake beep
-  ipfiremake bind
   ipfiremake dvdrtools
   ipfiremake dnsmasq
   ipfiremake dosfstools
diff --git a/src/patches/dhcp-4.2.0-PPP.patch b/src/patches/dhcp-4.2.0-PPP.patch
new file mode 100644 (file)
index 0000000..bef2be7
--- /dev/null
@@ -0,0 +1,150 @@
+diff -up dhcp-4.2.0-P1/client/dhc6.c.PPP dhcp-4.2.0-P1/client/dhc6.c
+--- dhcp-4.2.0-P1/client/dhc6.c.PPP    2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/client/dhc6.c        2010-11-09 15:54:12.000000000 +0100
+@@ -129,7 +129,7 @@ extern int stateless;
+  * is not how it is intended.  Upcoming rearchitecting the client should
+  * address this "one daemon model."
+  */
+-void
++isc_result_t
+ form_duid(struct data_string *duid, const char *file, int line)
+ {
+       struct interface_info *ip;
+@@ -141,6 +141,15 @@ form_duid(struct data_string *duid, cons
+       if (ip == NULL)
+               log_fatal("Impossible condition at %s:%d.", MDL);
++      while (ip && ip->hw_address.hbuf[0] == HTYPE_RESERVED) {
++              /* Try the other interfaces */
++              log_debug("Cannot form default DUID from interface %s.", ip->name);
++              ip = ip->next;
++      }
++      if (ip == NULL) {
++              return ISC_R_UNEXPECTED;
++      }
++
+       if ((ip->hw_address.hlen == 0) ||
+           (ip->hw_address.hlen > sizeof(ip->hw_address.hbuf)))
+               log_fatal("Impossible hardware address length at %s:%d.", MDL);
+@@ -176,6 +185,8 @@ form_duid(struct data_string *duid, cons
+               memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1,
+                      ip->hw_address.hlen - 1);
+       }
++
++      return ISC_R_SUCCESS;
+ }
+ /*
+@@ -5289,7 +5300,8 @@ make_client6_options(struct client_state
+        */
+       if ((oc = lookup_option(&dhcpv6_universe, *op,
+                               D6O_CLIENTID)) == NULL) {
+-              if (!option_cache(&oc, &default_duid, NULL, clientid_option,
++              if (default_duid.len == 0 ||
++                  !option_cache(&oc, &default_duid, NULL, clientid_option,
+                                 MDL))
+                       log_fatal("Failure assembling a DUID.");
+diff -up dhcp-4.2.0-P1/client/dhclient.c.PPP dhcp-4.2.0-P1/client/dhclient.c
+--- dhcp-4.2.0-P1/client/dhclient.c.PPP        2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/client/dhclient.c    2010-11-09 15:37:26.000000000 +0100
+@@ -911,8 +911,8 @@ main(int argc, char **argv) {
+                       if (default_duid.buffer != NULL)
+                               data_string_forget(&default_duid, MDL);
+-                      form_duid(&default_duid, MDL);
+-                      write_duid(&default_duid);
++                      if (form_duid(&default_duid, MDL) == ISC_R_SUCCESS)
++                              write_duid(&default_duid);
+               }
+               for (ip = interfaces ; ip != NULL ; ip = ip->next) {
+diff -up dhcp-4.2.0-P1/common/bpf.c.PPP dhcp-4.2.0-P1/common/bpf.c
+--- dhcp-4.2.0-P1/common/bpf.c.PPP     2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/common/bpf.c 2010-11-09 15:42:42.000000000 +0100
+@@ -599,6 +599,22 @@ get_hw_addr(const char *name, struct har
+                         memcpy(&hw->hbuf[1], LLADDR(sa), sa->sdl_alen);
+                         break;
+ #endif /* IFT_FDDI */
++#if defined(IFT_PPP)
++                case IFT_PPP:
++                        if (local_family != AF_INET6)
++                             log_fatal("Unsupported device type %d for \"%s\"",
++                                        sa->sdl_type, name);
++                        hw->hlen = 0;
++                        hw->hbuf[0] = HTYPE_RESERVED;
++                        /* 0xdeadbeef should never occur on the wire,
++                         *  and is a signature that something went wrong.
++                         */
++                        hw->hbuf[1] = 0xde;
++                        hw->hbuf[2] = 0xad;
++                        hw->hbuf[3] = 0xbe;
++                        hw->hbuf[4] = 0xef;
++                        break;
++#endif
+                 default:
+                         log_fatal("Unsupported device type %d for \"%s\"",
+                                   sa->sdl_type, name);
+diff -up dhcp-4.2.0-P1/common/lpf.c.PPP dhcp-4.2.0-P1/common/lpf.c
+--- dhcp-4.2.0-P1/common/lpf.c.PPP     2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/common/lpf.c 2010-11-09 15:45:40.000000000 +0100
+@@ -502,6 +502,22 @@ get_hw_addr(const char *name, struct har
+                       hw->hbuf[0] = HTYPE_FDDI;
+                       memcpy(&hw->hbuf[1], sa->sa_data, 16);
+                       break;
++#if defined(ARPHRD_PPP)
++              case ARPHRD_PPP:
++                      if (local_family != AF_INET6)
++                              log_fatal("Unsupported device type %d for \"%s\"",
++                                         sa->sa_family, name);
++                      hw->hlen = 0;
++                      hw->hbuf[0] = HTYPE_RESERVED;
++                      /* 0xdeadbeef should never occur on the wire,
++                       * and is a signature that something went wrong.
++                       */
++                      hw->hbuf[1] = 0xde;
++                      hw->hbuf[2] = 0xad;
++                      hw->hbuf[3] = 0xbe;
++                      hw->hbuf[4] = 0xef;
++                      break;
++#endif
+               default:
+                       log_fatal("Unsupported device type %ld for \"%s\"",
+                                 (long int)sa->sa_family, name);
+diff -up dhcp-4.2.0-P1/includes/dhcpd.h.PPP dhcp-4.2.0-P1/includes/dhcpd.h
+--- dhcp-4.2.0-P1/includes/dhcpd.h.PPP 2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/includes/dhcpd.h     2010-11-09 15:46:58.000000000 +0100
+@@ -2733,7 +2733,7 @@ void dhcpv4_client_assignments(void);
+ void dhcpv6_client_assignments(void);
+ /* dhc6.c */
+-void form_duid(struct data_string *duid, const char *file, int line);
++isc_result_t form_duid(struct data_string *duid, const char *file, int line);
+ void dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line);
+ void start_init6(struct client_state *client);
+ void start_info_request6(struct client_state *client);
+diff -up dhcp-4.2.0-P1/includes/dhcp.h.PPP dhcp-4.2.0-P1/includes/dhcp.h
+--- dhcp-4.2.0-P1/includes/dhcp.h.PPP  2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/includes/dhcp.h      2010-11-09 15:48:53.000000000 +0100
+@@ -80,6 +80,8 @@ struct dhcp_packet {
+ #define HTYPE_IEEE802 6               /* IEEE 802.2 Token Ring...     */
+ #define HTYPE_FDDI    8               /* FDDI...                      */
++#define HTYPE_RESERVED  0               /* RFC 5494 */
++
+ /* Magic cookie validating dhcp options field (and bootp vendor
+    extensions field). */
+ #define DHCP_OPTIONS_COOKIE   "\143\202\123\143"
+diff -up dhcp-4.2.0-P1/server/dhcpv6.c.PPP dhcp-4.2.0-P1/server/dhcpv6.c
+--- dhcp-4.2.0-P1/server/dhcpv6.c.PPP  2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/server/dhcpv6.c      2010-11-09 15:50:17.000000000 +0100
+@@ -300,6 +300,9 @@ generate_new_server_duid(void) {
+               if (p->hw_address.hlen > 0) {
+                       break;
+               }
++              if (p->next == NULL && p->hw_address.hbuf[0] == HTYPE_RESERVED) {
++                      log_error("Can not generate DUID from interfaces which do not have hardware addresses, please configure server-duid!");
++              }
+       }
+       if (p == NULL) {
+               return ISC_R_UNEXPECTED;
diff --git a/src/patches/dhcp-4.2.0-UseMulticast.patch b/src/patches/dhcp-4.2.0-UseMulticast.patch
new file mode 100644 (file)
index 0000000..319344a
--- /dev/null
@@ -0,0 +1,229 @@
+diff -up dhcp-4.2.0/server/dhcpv6.c.UseMulticast dhcp-4.2.0/server/dhcpv6.c
+--- dhcp-4.2.0/server/dhcpv6.c.UseMulticast    2010-06-01 19:30:00.000000000 +0200
++++ dhcp-4.2.0/server/dhcpv6.c 2010-07-21 16:17:30.000000000 +0200
+@@ -346,6 +346,48 @@ generate_new_server_duid(void) {
+ }
+ /*
++ * Is the D6O_UNICAST option defined in dhcpd.conf ?
++ */
++static isc_boolean_t unicast_option_defined;
++
++/*
++ * Did we already search dhcpd.conf for D6O_UNICAST option ?
++ * We need to store it here to not parse dhcpd.conf repeatedly.
++ */
++static isc_boolean_t unicast_option_parsed = ISC_FALSE;
++
++
++/*
++ * Is the D6O_UNICAST option defined in dhcpd.conf ?
++ */
++isc_boolean_t
++is_unicast_option_defined(void) {
++      struct option_state *opt_state;
++      struct option_cache *oc;
++
++      /*
++       * If we are looking for the unicast option for the first time
++       */
++      if (unicast_option_parsed == ISC_FALSE) {
++              unicast_option_parsed = ISC_TRUE;
++              opt_state = NULL;
++              if (!option_state_allocate(&opt_state, MDL)) {
++                      log_fatal("No memory for option state.");
++              }
++
++              execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
++                              opt_state, &global_scope, root_group, NULL);
++
++              oc = lookup_option(&dhcpv6_universe, opt_state, D6O_UNICAST);
++              unicast_option_defined = (oc != NULL);
++
++              option_state_dereference(&opt_state, MDL);
++      }
++
++      return (unicast_option_defined);
++}
++
++/*
+  * Get the client identifier from the packet.
+  */
+ isc_result_t
+@@ -1405,6 +1447,56 @@ lease_to_client(struct data_string *repl
+                                                   reply.shared->group);
+       }
++      /* reject unicast message, unless we set unicast option */
++      if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined())
++      /*
++       * RFC3315 section 18.2.1 (Request):
++       *
++       * When the server receives a Request message via unicast from a client
++       * to which the server has not sent a unicast option, the server
++       * discards the Request message and responds with a Reply message
++       * containing a Status Code option with the value UseMulticast, a Server
++       * Identifier option containing the server's DUID, the Client Identifier
++       * option from the client message, and no other options.
++       *
++       * Section 18.2.3 (Renew):
++       *
++       * When the server receives a Renew message via unicast from a client to
++       * which the server has not sent a unicast option, the server discards
++       * the Renew message and responds with a Reply message containing a
++       * Status Code option with the value UseMulticast, a Server Identifier
++       * option containing the server's DUID, the Client Identifier option
++       * from the client message, and no other options.
++       */
++      {
++              /* Set the UseMulticast status code. */
++              if (!set_status_code(STATUS_UseMulticast,
++                                      "Unicast not allowed by server.",
++                                      reply.opt_state)) {
++                      log_error("lease_to_client: Unable to set "
++                                      "UseMulticast status code.");
++                      goto exit;
++              }
++
++              /* Rewind the cursor to the start. */
++              reply.cursor = REPLY_OPTIONS_INDEX;
++
++              /*
++               * Produce an reply that includes only:
++               *
++               * Status code.
++               * Server DUID.
++               * Client DUID.
++               */
++              reply.cursor += store_options6((char *)reply.buf.data +
++                                      reply.cursor,
++                                      sizeof(reply.buf) -
++                                      reply.cursor,
++                                      reply.opt_state, reply.packet,
++                                      required_opts_NAA,
++                                      NULL);
++      } else if (no_resources_avail && (reply.ia_count != 0) &&
++          (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
+       /*
+        * RFC3315 section 17.2.2 (Solicit):
+        *
+@@ -1429,8 +1521,6 @@ lease_to_client(struct data_string *repl
+        * the server.
+        * Sends a Renew/Rebind if the IA is not in the Reply message.
+        */
+-      if (no_resources_avail && (reply.ia_count != 0) &&
+-          (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
+       {
+               /* Set the NoAddrsAvail status code. */
+               if (!set_status_code(STATUS_NoAddrsAvail,
+@@ -4128,7 +4218,6 @@ dhcpv6_solicit(struct data_string *reply
+  * Very similar to Solicit handling, except the server DUID is required.
+  */
+-/* TODO: reject unicast messages, unless we set unicast option */
+ static void
+ dhcpv6_request(struct data_string *reply_ret, struct packet *packet) {
+       struct data_string client_id;
+@@ -4443,7 +4532,6 @@ exit:
+  * except for the error code of when addresses don't match.
+  */
+-/* TODO: reject unicast messages, unless we set unicast option */
+ static void
+ dhcpv6_renew(struct data_string *reply, struct packet *packet) {
+       struct data_string client_id;
+@@ -4688,18 +4776,60 @@ iterate_over_ia_na(struct data_string *r
+               goto exit;
+       }
+-      snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
+-      if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
+-              goto exit;
+-      }
++      /* reject unicast message, unless we set unicast option */
++      if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined()) {
++              /*
++               * RFC3315 section 18.2.6 (Release):
++               *
++               * When the server receives a Release message via unicast from a client
++               * to which the server has not sent a unicast option, the server
++               * discards the Release message and responds with a Reply message
++               * containing a Status Code option with value UseMulticast, a Server
++               * Identifier option containing the server's DUID, the Client Identifier
++               * option from the client message, and no other options.
++               *
++               * Section 18.2.7 (Decline):
++               *
++               * When the server receives a Decline message via unicast from a client
++               * to which the server has not sent a unicast option, the server
++               * discards the Decline message and responds with a Reply message
++               * containing a Status Code option with the value UseMulticast, a Server
++               * Identifier option containing the server's DUID, the Client Identifier
++               * option from the client message, and no other options.
++               */
++              snprintf(status_msg, sizeof(status_msg),
++                               "%s received unicast.", packet_type);
++              if (!set_status_code(STATUS_UseMulticast, status_msg, opt_state)) {
++                      goto exit;
++              }
+-      /* 
+-       * Add our options that are not associated with any IA_NA or IA_TA. 
+-       */
+-      reply_ofs += store_options6(reply_data+reply_ofs,
+-                                  sizeof(reply_data)-reply_ofs, 
++              /*
++               * Produce an reply that includes only:
++               *
++               * Status code.
++               * Server DUID.
++               * Client DUID.
++               */
++              reply_ofs += store_options6(reply_data+reply_ofs,
++                                  sizeof(reply_data)-reply_ofs,
+                                   opt_state, packet,
+-                                  required_opts, NULL);
++                                  required_opts_NAA, NULL);
++
++              goto return_reply;
++      } else {
++              snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
++              if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
++                      goto exit;
++              }
++
++              /*
++               * Add our options that are not associated with any IA_NA or IA_TA.
++               */
++              reply_ofs += store_options6(reply_data+reply_ofs,
++                                          sizeof(reply_data)-reply_ofs,
++                                          opt_state, packet,
++                                          required_opts, NULL);
++      }
+       /*
+        * Loop through the IA_NA reported by the client, and deal with
+@@ -4838,6 +4968,7 @@ iterate_over_ia_na(struct data_string *r
+       /* 
+        * Return our reply to the caller.
+        */
++return_reply:
+       reply_ret->len = reply_ofs;
+       reply_ret->buffer = NULL;
+       if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
+@@ -4883,7 +5014,6 @@ exit:
+  * we still need to be aware of this possibility.
+  */
+-/* TODO: reject unicast messages, unless we set unicast option */
+ /* TODO: IA_TA */
+ static void
+ dhcpv6_decline(struct data_string *reply, struct packet *packet) {
+@@ -5355,7 +5485,6 @@ exit:
+  * Release means a client is done with the leases.
+  */
+-/* TODO: reject unicast messages, unless we set unicast option */
+ static void
+ dhcpv6_release(struct data_string *reply, struct packet *packet) {
+       struct data_string client_id;
diff --git a/src/patches/dhcp-4.2.0-add_timeout_when_NULL.patch b/src/patches/dhcp-4.2.0-add_timeout_when_NULL.patch
new file mode 100644 (file)
index 0000000..4784d5a
--- /dev/null
@@ -0,0 +1,14 @@
+diff -up dhcp-4.2.0/common/dispatch.c.dracut dhcp-4.2.0/common/dispatch.c
+--- dhcp-4.2.0/common/dispatch.c.dracut        2010-06-01 19:29:59.000000000 +0200
++++ dhcp-4.2.0/common/dispatch.c       2010-07-21 16:10:09.000000000 +0200
+@@ -189,6 +189,10 @@ void add_timeout (when, where, what, ref
+       isc_interval_t interval;
+       isc_time_t expires;
++      if (when == NULL) {
++              return;
++      }
++
+       /* See if this timeout supersedes an existing timeout. */
+       t = (struct timeout *)0;
+       for (q = timeouts; q; q = q->next) {
diff --git a/src/patches/dhcp-4.2.0-default-requested-options.patch b/src/patches/dhcp-4.2.0-default-requested-options.patch
new file mode 100644 (file)
index 0000000..fea8a4b
--- /dev/null
@@ -0,0 +1,44 @@
+diff -up dhcp-4.2.0/client/clparse.c.requested dhcp-4.2.0/client/clparse.c
+--- dhcp-4.2.0/client/clparse.c.requested      2010-07-21 13:29:05.000000000 +0200
++++ dhcp-4.2.0/client/clparse.c        2010-07-21 13:50:29.000000000 +0200
+@@ -37,7 +37,7 @@
+ struct client_config top_level_config;
+-#define NUM_DEFAULT_REQUESTED_OPTS    9
++#define NUM_DEFAULT_REQUESTED_OPTS    14
+ struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
+ static void parse_client_default_duid(struct parse *cfile);
+@@ -111,6 +111,31 @@ isc_result_t read_client_conf ()
+       option_code_hash_lookup(&default_requested_options[8],
+                               dhcpv6_universe.code_hash, &code, 0, MDL);
++      /* 10 */
++      code = DHO_NIS_DOMAIN;
++      option_code_hash_lookup(&default_requested_options[9],
++                              dhcp_universe.code_hash, &code, 0, MDL);
++
++      /* 11 */
++      code = DHO_NIS_SERVERS;
++      option_code_hash_lookup(&default_requested_options[10],
++                              dhcp_universe.code_hash, &code, 0, MDL);
++
++      /* 12 */
++      code = DHO_NTP_SERVERS;
++      option_code_hash_lookup(&default_requested_options[11],
++                              dhcp_universe.code_hash, &code, 0, MDL);
++
++      /* 13 */
++      code = DHO_INTERFACE_MTU;
++      option_code_hash_lookup(&default_requested_options[12],
++                              dhcp_universe.code_hash, &code, 0, MDL);
++
++      /* 14 */
++      code = DHO_DOMAIN_SEARCH;
++      option_code_hash_lookup(&default_requested_options[13],
++                              dhcp_universe.code_hash, &code, 0, MDL);
++
+       for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
+               if (default_requested_options[code] == NULL)
+                       log_fatal("Unable to find option definition for "
diff --git a/src/patches/dhcp-4.2.0-dhclient-decline-backoff.patch b/src/patches/dhcp-4.2.0-dhclient-decline-backoff.patch
new file mode 100644 (file)
index 0000000..81bec7b
--- /dev/null
@@ -0,0 +1,63 @@
+diff -up dhcp-4.2.0/client/dhclient.c.backoff dhcp-4.2.0/client/dhclient.c
+--- dhcp-4.2.0/client/dhclient.c.backoff       2010-07-21 13:37:03.000000000 +0200
++++ dhcp-4.2.0/client/dhclient.c       2010-07-21 13:38:31.000000000 +0200
+@@ -1208,6 +1208,8 @@ void state_init (cpp)
+       void *cpp;
+ {
+       struct client_state *client = cpp;
++      enum dhcp_state init_state = client->state;
++      struct timeval tv;
+       ASSERT_STATE(state, S_INIT);
+@@ -1220,9 +1222,18 @@ void state_init (cpp)
+       client -> first_sending = cur_time;
+       client -> interval = client -> config -> initial_interval;
+-      /* Add an immediate timeout to cause the first DHCPDISCOVER packet
+-         to go out. */
+-      send_discover (client);
++      if (init_state != S_DECLINED) {
++              /* Add an immediate timeout to cause the first DHCPDISCOVER packet
++                 to go out. */
++              send_discover(client);
++      } else {
++              /* We've received an OFFER and it has been DECLINEd by dhclient-script.
++               * wait for a random time between 1 and backoff_cutoff seconds before
++               * trying again. */
++              tv . tv_sec = cur_time + ((1 + (random() >> 2)) %  client->config->backoff_cutoff);
++              tv . tv_usec = 0;
++              add_timeout(&tv, send_discover, client, 0, 0);
++      }
+ }
+ /*
+@@ -1501,6 +1512,7 @@ void bind_lease (client)
+               send_decline (client);
+               destroy_client_lease (client -> new);
+               client -> new = (struct client_lease *)0;
++              client -> state = S_DECLINED;
+               state_init (client);
+               return;
+       }
+@@ -3711,6 +3723,7 @@ void client_location_changed ()
+                             case S_INIT:
+                             case S_REBINDING:
+                             case S_STOPPED:
++                            case S_DECLINED:
+                               break;
+                       }
+                       client -> state = S_INIT;
+diff -up dhcp-4.2.0/includes/dhcpd.h.backoff dhcp-4.2.0/includes/dhcpd.h
+--- dhcp-4.2.0/includes/dhcpd.h.backoff        2010-07-21 13:29:05.000000000 +0200
++++ dhcp-4.2.0/includes/dhcpd.h        2010-07-21 13:38:31.000000000 +0200
+@@ -1056,7 +1056,8 @@ enum dhcp_state {
+       S_BOUND = 5,
+       S_RENEWING = 6,
+       S_REBINDING = 7,
+-      S_STOPPED = 8
++      S_STOPPED = 8,
++      S_DECLINED = 9
+ };
+ /* Authentication and BOOTP policy possibilities (not all values work
diff --git a/src/patches/dhcp-4.2.0-errwarn-message.patch b/src/patches/dhcp-4.2.0-errwarn-message.patch
new file mode 100644 (file)
index 0000000..a0f70cd
--- /dev/null
@@ -0,0 +1,30 @@
+diff -up dhcp-4.2.0/omapip/errwarn.c.errwarn dhcp-4.2.0/omapip/errwarn.c
+--- dhcp-4.2.0/omapip/errwarn.c.errwarn        2009-07-23 20:52:21.000000000 +0200
++++ dhcp-4.2.0/omapip/errwarn.c        2010-07-21 13:23:47.000000000 +0200
+@@ -76,20 +76,13 @@ void log_fatal (const char * fmt, ... )
+ #if !defined (NOMINUM)
+   log_error ("%s", "");
+-  log_error ("If you did not get this software from ftp.isc.org, please");
+-  log_error ("get the latest from ftp.isc.org and install that before");
+-  log_error ("requesting help.");
++  log_error ("This version of ISC DHCP is based on the release available");
++  log_error ("on ftp.isc.org.  Features have been added and other changes");
++  log_error ("have been made to the base software release in order to make");
++  log_error ("it work better with this distribution.");
+   log_error ("%s", "");
+-  log_error ("If you did get this software from ftp.isc.org and have not");
+-  log_error ("yet read the README, please read it before requesting help.");
+-  log_error ("If you intend to request help from the dhcp-server@isc.org");
+-  log_error ("mailing list, please read the section on the README about");
+-  log_error ("submitting bug reports and requests for help.");
+-  log_error ("%s", "");
+-  log_error ("Please do not under any circumstances send requests for");
+-  log_error ("help directly to the authors of this software - please");
+-  log_error ("send them to the appropriate mailing list as described in");
+-  log_error ("the README file.");
++  log_error ("Please report for this software via the Red Hat Bugzilla site:");
++  log_error ("    http://bugzilla.redhat.com");
+   log_error ("%s", "");
+   log_error ("exiting.");
+ #endif
diff --git a/src/patches/dhcp-4.2.0-garbage-chars.patch b/src/patches/dhcp-4.2.0-garbage-chars.patch
new file mode 100644 (file)
index 0000000..118ff3f
--- /dev/null
@@ -0,0 +1,12 @@
+diff -up dhcp-4.2.0/common/tables.c.garbage dhcp-4.2.0/common/tables.c
+--- dhcp-4.2.0/common/tables.c.garbage 2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.0/common/tables.c 2010-07-21 14:40:56.000000000 +0200
+@@ -207,7 +207,7 @@ static struct option dhcp_options[] = {
+       { "netinfo-server-tag", "t",            &dhcp_universe, 113, 1 },
+       { "default-url", "t",                   &dhcp_universe, 114, 1 },
+       { "subnet-selection", "I",              &dhcp_universe, 118, 1 },
+-      { "domain-search", "Dc",                &dhcp_universe, 119, 1 },
++      { "domain-search", "D",         &dhcp_universe, 119, 1 },
+       { "vivco", "Evendor-class.",            &dhcp_universe, 124, 1 },
+       { "vivso", "Evendor.",                  &dhcp_universe, 125, 1 },
+ #if 0
diff --git a/src/patches/dhcp-4.2.0-honor-expired.patch b/src/patches/dhcp-4.2.0-honor-expired.patch
new file mode 100644 (file)
index 0000000..0ae9128
--- /dev/null
@@ -0,0 +1,49 @@
+diff -up dhcp-4.2.0/client/dhc6.c.honor-expired dhcp-4.2.0/client/dhc6.c
+--- dhcp-4.2.0/client/dhc6.c.honor-expired     2010-10-07 12:55:37.000000000 +0200
++++ dhcp-4.2.0/client/dhc6.c   2010-10-07 12:56:43.000000000 +0200
+@@ -1405,6 +1405,32 @@ start_info_request6(struct client_state 
+               go_daemon();
+ }
++/* Run through the addresses in lease and return true if there's any unexpired.
++ * Return false otherwise.
++ */
++isc_boolean_t
++unexpired_address_in_lease(struct dhc6_lease *lease)
++{
++      struct dhc6_ia *ia;
++      struct dhc6_addr *addr;
++
++      for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
++              for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
++                      if (addr->flags & DHC6_ADDR_EXPIRED)
++                              continue;
++
++                      if (addr->starts + addr->max_life > cur_time) {
++                              return ISC_TRUE;
++                      }
++              }
++      }
++
++      log_info("PRC: Previous lease is devoid of active addresses."
++               "  Re-initializing.");
++
++      return ISC_FALSE;
++}
++
+ /*
+  * start_confirm6() kicks off an "init-reboot" version of the process, at
+  * startup to find out if old bindings are 'fair' and at runtime whenever
+@@ -1417,8 +1446,10 @@ start_confirm6(struct client_state *clie
+       /* If there is no active lease, there is nothing to check. */
+       if ((client->active_lease == NULL) ||
+-          !active_prefix(client) ||
+-          client->active_lease->released) {
++              !active_prefix(client) ||
++              client->active_lease->released ||
++              !unexpired_address_in_lease(client->active_lease)) {
++              dhc6_lease_destroy(&client->active_lease, MDL);
+               start_init6(client);
+               return;
+       }
diff --git a/src/patches/dhcp-4.2.0-inherit-leases.patch b/src/patches/dhcp-4.2.0-inherit-leases.patch
new file mode 100644 (file)
index 0000000..052f642
--- /dev/null
@@ -0,0 +1,34 @@
+diff -up dhcp-4.2.0/client/dhclient.c.inherit dhcp-4.2.0/client/dhclient.c
+--- dhcp-4.2.0/client/dhclient.c.inherit       2010-07-21 14:33:44.000000000 +0200
++++ dhcp-4.2.0/client/dhclient.c       2010-07-21 14:40:05.000000000 +0200
+@@ -2322,6 +2322,7 @@ void send_request (cpp)
+ {
+       struct client_state *client = cpp;
++      int i;
+       int result;
+       int interval;
+       struct sockaddr_in destination;
+@@ -2381,6 +2382,22 @@ void send_request (cpp)
+               /* Now do a preinit on the interface so that we can
+                  discover a new address. */
+               script_init (client, "PREINIT", (struct string_list *)0);
++
++              /* Has an active lease */
++              if (client -> interface -> addresses != NULL) {
++                      for (i = 0; i < client -> interface -> address_count; i++) {
++                              if (client -> active &&
++                                  client -> active -> is_bootp &&
++                                  client -> active -> expiry > cur_time &&
++                                  client -> interface -> addresses[i].s_addr != 0 &&
++                                  client -> active -> address.len == 4 &&
++                                  memcpy (client -> active -> address.iabuf, &(client -> interface -> addresses[i]), 4) == 0) {
++                                      client_envadd (client, "", "keep_old_ip", "%s", "yes");
++                                      break;
++                              }
++                      }
++              }
++
+               if (client -> alias)
+                       script_write_params (client, "alias_",
+                                            client -> alias);
diff --git a/src/patches/dhcp-4.2.0-logpid.patch b/src/patches/dhcp-4.2.0-logpid.patch
new file mode 100644 (file)
index 0000000..c24adb1
--- /dev/null
@@ -0,0 +1,12 @@
+diff -up dhcp-4.2.0/client/dhclient.c.logpid dhcp-4.2.0/client/dhclient.c
+--- dhcp-4.2.0/client/dhclient.c.logpid        2010-07-21 16:13:52.000000000 +0200
++++ dhcp-4.2.0/client/dhclient.c       2010-07-21 16:16:51.000000000 +0200
+@@ -154,7 +154,7 @@ main(int argc, char **argv) {
+       else if (fd != -1)
+               close(fd);
+-      openlog("dhclient", LOG_NDELAY, LOG_DAEMON);
++      openlog("dhclient", LOG_NDELAY | LOG_PID, LOG_DAEMON);
+ #if !(defined(DEBUG) || defined(__CYGWIN32__))
+       setlogmask(LOG_UPTO(LOG_INFO));
diff --git a/src/patches/dhcp-4.2.0-missing-ipv6-not-fatal.patch b/src/patches/dhcp-4.2.0-missing-ipv6-not-fatal.patch
new file mode 100644 (file)
index 0000000..b604115
--- /dev/null
@@ -0,0 +1,40 @@
+diff -up dhcp-4.2.0/common/discover.c.noipv6 dhcp-4.2.0/common/discover.c
+--- dhcp-4.2.0/common/discover.c.noipv6        2010-07-21 14:31:13.000000000 +0200
++++ dhcp-4.2.0/common/discover.c       2010-07-21 16:04:57.000000000 +0200
+@@ -443,7 +443,7 @@ begin_iface_scan(struct iface_conf_list 
+       }
+ #ifdef DHCPv6
+-      if (local_family == AF_INET6) {
++      if ((local_family == AF_INET6) && !access("/proc/net/if_inet6", R_OK)) {
+               ifaces->fp6 = fopen("/proc/net/if_inet6", "re");
+               if (ifaces->fp6 == NULL) {
+                       log_error("Error opening '/proc/net/if_inet6' to "
+@@ -454,6 +454,8 @@ begin_iface_scan(struct iface_conf_list 
+                       ifaces->fp = NULL;
+                       return 0;
+               }
++      } else {
++              ifaces->fp6 = NULL;
+       }
+ #endif
+@@ -721,7 +723,7 @@ next_iface(struct iface_info *info, int 
+               return 1;
+       }
+ #ifdef DHCPv6
+-      if (!(*err)) {
++      if (!(*err) && ifaces->fp6) {
+               if (local_family == AF_INET6)
+                       return next_iface6(info, err, ifaces);
+       }
+@@ -740,7 +742,8 @@ end_iface_scan(struct iface_conf_list *i
+       ifaces->sock = -1;
+ #ifdef DHCPv6
+       if (local_family == AF_INET6) {
+-              fclose(ifaces->fp6);
++              if (ifaces->fp6)
++                      fclose(ifaces->fp6);
+               ifaces->fp6 = NULL;
+       }
+ #endif
diff --git a/src/patches/dhcp-4.2.0-noprefixavail.patch b/src/patches/dhcp-4.2.0-noprefixavail.patch
new file mode 100644 (file)
index 0000000..729a172
--- /dev/null
@@ -0,0 +1,140 @@
+diff -up dhcp-4.2.0/server/dhcpv6.c.noprefixavail dhcp-4.2.0/server/dhcpv6.c
+--- dhcp-4.2.0/server/dhcpv6.c.noprefixavail   2010-10-07 13:48:45.000000000 +0200
++++ dhcp-4.2.0/server/dhcpv6.c 2010-10-13 11:00:25.000000000 +0200
+@@ -1134,7 +1134,7 @@ try_client_v6_prefix(struct iasubopt **p
+               return DHCP_R_INVALIDARG;
+       }
+       tmp_plen = (int) requested_pref->data[0];
+-      if ((tmp_plen < 3) || (tmp_plen > 128)) {
++      if ((tmp_plen < 3) || (tmp_plen > 128) ||((int)tmp_plen != pool->units)) {
+               return ISC_R_FAILURE;
+       }
+       memcpy(&tmp_pref, requested_pref->data + 1, sizeof(tmp_pref));
+@@ -1147,9 +1147,8 @@ try_client_v6_prefix(struct iasubopt **p
+               return ISC_R_FAILURE;
+       }
+-      if (((int)tmp_plen != pool->units) ||
+-          !ipv6_in_pool(&tmp_pref, pool)) {
+-              return ISC_R_FAILURE;
++      if (!ipv6_in_pool(&tmp_pref, pool)) {
++              return ISC_R_ADDRNOTAVAIL;
+       }
+       if (prefix6_exists(pool, &tmp_pref, tmp_plen)) {
+@@ -1409,13 +1408,6 @@ lease_to_client(struct data_string *repl
+               if ((status != ISC_R_SUCCESS) &&
+                   (status != ISC_R_NORESOURCES))
+                       goto exit;
+-
+-              /*
+-               * If any prefix cannot be given to any IA_PD, then
+-               * set the NoPrefixAvail status code.
+-               */
+-              if (reply.client_resources == 0)
+-                      no_resources_avail = ISC_TRUE;
+       }
+       /*
+@@ -1549,36 +1541,6 @@ lease_to_client(struct data_string *repl
+                                              reply.opt_state, reply.packet,
+                                              required_opts_NAA,
+                                              NULL);
+-      } else if (no_resources_avail && (reply.ia_count == 0) &&
+-                 (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
+-      {
+-              /* Set the NoPrefixAvail status code. */
+-              if (!set_status_code(STATUS_NoPrefixAvail,
+-                                   "No prefixes available for this "
+-                                   "interface.", reply.opt_state)) {
+-                      log_error("lease_to_client: Unable to set "
+-                                "NoPrefixAvail status code.");
+-                      goto exit;
+-              }
+-
+-              /* Rewind the cursor to the start. */
+-              reply.cursor = REPLY_OPTIONS_INDEX;
+-
+-              /*
+-               * Produce an advertise that includes only:
+-               *
+-               * Status code.
+-               * Server DUID.
+-               * Client DUID.
+-               */
+-              reply.buf.reply.msg_type = DHCPV6_ADVERTISE;
+-              reply.cursor += store_options6((char *)reply.buf.data +
+-                                                      reply.cursor,
+-                                             sizeof(reply.buf) -
+-                                                      reply.cursor,
+-                                             reply.opt_state, reply.packet,
+-                                             required_opts_NAA,
+-                                             NULL);
+       } else {
+               /*
+                * Having stored the client's IA's, store any options that
+@@ -2793,16 +2755,18 @@ find_client_temporaries(struct reply_sta
+  */
+ static isc_result_t
+ reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
+-      isc_result_t status = ISC_R_NORESOURCES;
++      isc_result_t status = ISC_R_ADDRNOTAVAIL;
+       struct ipv6_pool *pool;
+       int i;
+       struct data_string data_addr;
+       if ((reply == NULL) || (reply->shared == NULL) ||
+-          (reply->shared->ipv6_pools == NULL) || (addr == NULL) ||
+-          (reply->lease != NULL))
++          (addr == NULL) || (reply->lease != NULL))
+               return DHCP_R_INVALIDARG;
++      if (reply->shared->ipv6_pools == NULL)
++              return ISC_R_ADDRNOTAVAIL;
++
+       memset(&data_addr, 0, sizeof(data_addr));
+       data_addr.len = addr->len;
+       data_addr.data = addr->iabuf;
+@@ -3314,7 +3278,9 @@ reply_process_ia_pd(struct reply_state *
+               if (status == ISC_R_CANCELED)
+                       break;
+-              if ((status != ISC_R_SUCCESS) && (status != ISC_R_ADDRINUSE))
++              if ((status != ISC_R_SUCCESS) &&
++                  (status != ISC_R_ADDRINUSE) &&
++                  (status != ISC_R_ADDRNOTAVAIL))
+                       goto cleanup;
+       }
+@@ -3594,7 +3560,8 @@ reply_process_prefix(struct reply_state 
+                       /* Either error out or skip this prefix. */
+                       if ((status != ISC_R_SUCCESS) && 
+-                          (status != ISC_R_ADDRINUSE)) 
++                          (status != ISC_R_ADDRINUSE) &&
++                          (status != ISC_R_ADDRNOTAVAIL))
+                               goto cleanup;
+                       if (reply->lease == NULL) {
+@@ -3773,16 +3740,18 @@ prefix_is_owned(struct reply_state *repl
+ static isc_result_t
+ reply_process_try_prefix(struct reply_state *reply,
+                        struct iaddrcidrnet *pref) {
+-      isc_result_t status = ISC_R_NORESOURCES;
++      isc_result_t status = ISC_R_ADDRNOTAVAIL;
+       struct ipv6_pool *pool;
+       int i;
+       struct data_string data_pref;
+       if ((reply == NULL) || (reply->shared == NULL) ||
+-          (reply->shared->ipv6_pools == NULL) || (pref == NULL) ||
+-          (reply->lease != NULL))
++          (pref == NULL) || (reply->lease != NULL))
+               return DHCP_R_INVALIDARG;
++      if (reply->shared->ipv6_pools == NULL)
++              return ISC_R_ADDRNOTAVAIL;
++
+       memset(&data_pref, 0, sizeof(data_pref));
+       data_pref.len = 17;
+       if (!buffer_allocate(&data_pref.buffer, data_pref.len, MDL)) {
diff --git a/src/patches/dhcp-4.2.0-paths.patch b/src/patches/dhcp-4.2.0-paths.patch
new file mode 100644 (file)
index 0000000..54c7aba
--- /dev/null
@@ -0,0 +1,45 @@
+diff -up dhcp-4.2.0/includes/dhcpd.h.paths dhcp-4.2.0/includes/dhcpd.h
+--- dhcp-4.2.0/includes/dhcpd.h.paths  2010-07-21 13:55:42.000000000 +0200
++++ dhcp-4.2.0/includes/dhcpd.h        2010-07-21 14:29:57.000000000 +0200
+@@ -1390,15 +1390,15 @@ typedef unsigned char option_mask [16];
+ #else /* !DEBUG */
+ #ifndef _PATH_DHCPD_CONF
+-#define _PATH_DHCPD_CONF      "/etc/dhcpd.conf"
++#define _PATH_DHCPD_CONF      "/etc/dhcp/dhcpd.conf"
+ #endif /* DEBUG */
+ #ifndef _PATH_DHCPD_DB
+-#define _PATH_DHCPD_DB                LOCALSTATEDIR"/db/dhcpd.leases"
++#define _PATH_DHCPD_DB                LOCALSTATEDIR"/dhcpd/dhcpd.leases"
+ #endif
+ #ifndef _PATH_DHCPD6_DB
+-#define _PATH_DHCPD6_DB               LOCALSTATEDIR"/db/dhcpd6.leases"
++#define _PATH_DHCPD6_DB               LOCALSTATEDIR"/dhcpd/dhcpd6.leases"
+ #endif
+ #ifndef _PATH_DHCPD_PID
+@@ -1412,7 +1412,7 @@ typedef unsigned char option_mask [16];
+ #endif /* DEBUG */
+ #ifndef _PATH_DHCLIENT_CONF
+-#define _PATH_DHCLIENT_CONF   "/etc/dhclient.conf"
++#define _PATH_DHCLIENT_CONF   "/etc/dhcp/dhclient.conf"
+ #endif
+ #ifndef _PATH_DHCLIENT_SCRIPT
+@@ -1428,11 +1428,11 @@ typedef unsigned char option_mask [16];
+ #endif
+ #ifndef _PATH_DHCLIENT_DB
+-#define _PATH_DHCLIENT_DB     LOCALSTATEDIR"/db/dhclient.leases"
++#define _PATH_DHCLIENT_DB     LOCALSTATEDIR"/dhclient/dhclient.leases"
+ #endif
+ #ifndef _PATH_DHCLIENT6_DB
+-#define _PATH_DHCLIENT6_DB    LOCALSTATEDIR"/db/dhclient6.leases"
++#define _PATH_DHCLIENT6_DB    LOCALSTATEDIR"/dhclient/dhclient6.leases"
+ #endif
+ #ifndef _PATH_RESOLV_CONF
diff --git a/src/patches/dhcp-4.2.0-release-by-ifup.patch b/src/patches/dhcp-4.2.0-release-by-ifup.patch
new file mode 100644 (file)
index 0000000..300c5f3
--- /dev/null
@@ -0,0 +1,85 @@
+diff -up dhcp-4.2.0/client/dhclient.c.ifup dhcp-4.2.0/client/dhclient.c
+--- dhcp-4.2.0/client/dhclient.c.ifup  2010-07-21 13:30:10.000000000 +0200
++++ dhcp-4.2.0/client/dhclient.c       2010-07-21 13:37:03.000000000 +0200
+@@ -497,9 +497,81 @@ main(int argc, char **argv) {
+                                       kill(oldpid, SIGTERM);
+                       }
+                       fclose(pidfd);
++              } else {
++                      /* handle release for interfaces requested with Red Hat
++                       * /sbin/ifup - pidfile will be /var/run/dhclient-$interface.pid
++                       */
++
++                      if ((path_dhclient_pid == NULL) || (*path_dhclient_pid == '\0'))
++                              path_dhclient_pid = "/var/run/dhclient.pid";
++
++                      char *new_path_dhclient_pid;
++                      struct interface_info *ip;
++                      int pdp_len = strlen(path_dhclient_pid), pfx, dpfx;
++
++                      /* find append point: beginning of any trailing '.pid'
++                       * or '-$IF.pid' */
++                      for (pfx=pdp_len; (pfx >= 0) && (path_dhclient_pid[pfx] != '.') && (path_dhclient_pid[pfx] != '/'); pfx--);
++                              if (pfx == -1)
++                                      pfx = pdp_len;
++
++                      if (path_dhclient_pid[pfx] == '/')
++                              pfx += 1;
++
++                      for (dpfx=pfx; (dpfx >= 0) && (path_dhclient_pid[dpfx] != '-') && (path_dhclient_pid[dpfx] != '/'); dpfx--);
++                              if ((dpfx > -1) && (path_dhclient_pid[dpfx] != '/'))
++                                      pfx = dpfx;
++
++                      for (ip = interfaces; ip; ip = ip->next) {
++                              if (interfaces_requested && (ip->flags & (INTERFACE_REQUESTED))) {
++                                      int n_len = strlen(ip->name);
++
++                                      new_path_dhclient_pid = (char*) malloc(pfx + n_len + 6);
++                                      strncpy(new_path_dhclient_pid, path_dhclient_pid, pfx);
++                                      sprintf(new_path_dhclient_pid + pfx, "-%s.pid", ip->name);
++
++                                      if ((pidfd = fopen(new_path_dhclient_pid, "r")) != NULL) {
++                                              e = fscanf(pidfd, "%ld\n", &temp);
++                                              oldpid = (pid_t)temp;
++
++                                              if (e != 0 && e != EOF) {
++                                                      if (oldpid) {
++                                                              if (kill(oldpid, SIGTERM) == 0)
++                                                                      unlink(path_dhclient_pid);
++                                                      }
++                                              }
++
++                                              fclose(pidfd);
++                                      }
++
++                                      free(new_path_dhclient_pid);
++                              }
++                      }
++              }
++      } else {
++              FILE *pidfp = NULL;
++              long temp = 0;
++              pid_t dhcpid = 0;
++              int dhc_running = 0;
++              char procfn[256] = "";
++
++              if ((pidfp = fopen(path_dhclient_pid, "r")) != NULL) {
++                      if ((fscanf(pidfp, "%ld", &temp)==1) && ((dhcpid=(pid_t)temp) > 0)) {
++                              snprintf(procfn,256,"/proc/%u",dhcpid);
++                              dhc_running = (access(procfn, F_OK) == 0);
++                      }
++
++                      fclose(pidfp);
++              }
++
++              if (dhc_running) {
++                      log_fatal("dhclient(%u) is already running - exiting. ", dhcpid);
++                      return(1);
+               }
+       }
++      write_client_pid_file();
++
+       if (!quiet) {
+               log_info("%s %s", message, PACKAGE_VERSION);
+               log_info(copyright);
diff --git a/src/patches/dhcp-4.2.0-unicast-bootp.patch b/src/patches/dhcp-4.2.0-unicast-bootp.patch
new file mode 100644 (file)
index 0000000..78bc078
--- /dev/null
@@ -0,0 +1,99 @@
+diff -up dhcp-4.2.0/server/bootp.c.unicast dhcp-4.2.0/server/bootp.c
+--- dhcp-4.2.0/server/bootp.c.unicast  2009-11-20 02:49:03.000000000 +0100
++++ dhcp-4.2.0/server/bootp.c  2010-07-21 13:40:25.000000000 +0200
+@@ -58,6 +58,7 @@ void bootp (packet)
+       char msgbuf [1024];
+       int ignorep;
+       int peer_has_leases = 0;
++      int norelay = 0;
+       if (packet -> raw -> op != BOOTREQUEST)
+               return;
+@@ -73,7 +74,7 @@ void bootp (packet)
+                ? inet_ntoa (packet -> raw -> giaddr)
+                : packet -> interface -> name);
+-      if (!locate_network (packet)) {
++      if ((norelay = locate_network (packet)) == 0) {
+               log_info ("%s: network unknown", msgbuf);
+               return;
+       }
+@@ -390,6 +391,13 @@ void bootp (packet)
+                                             from, &to, &hto);
+                       goto out;
+               }
++      } else if (norelay == 2) {
++              to.sin_addr = raw.ciaddr;
++              to.sin_port = remote_port;
++              if (fallback_interface) {
++                      result = send_packet (fallback_interface, (struct packet *)0, &raw, outgoing.packet_length, from, &to, &hto);
++                      goto out;
++              }
+       /* If it comes from a client that already knows its address
+          and is not requesting a broadcast response, and we can
+diff -up dhcp-4.2.0/server/dhcp.c.unicast dhcp-4.2.0/server/dhcp.c
+--- dhcp-4.2.0/server/dhcp.c.unicast   2010-06-01 19:29:59.000000000 +0200
++++ dhcp-4.2.0/server/dhcp.c   2010-07-21 13:40:25.000000000 +0200
+@@ -4185,6 +4185,7 @@ int locate_network (packet)
+       struct data_string data;
+       struct subnet *subnet = (struct subnet *)0;
+       struct option_cache *oc;
++      int norelay = 0;
+       /* See if there's a Relay Agent Link Selection Option, or a
+        * Subnet Selection Option.  The Link-Select and Subnet-Select
+@@ -4200,12 +4201,24 @@ int locate_network (packet)
+          from the interface, if there is one.   If not, fail. */
+       if (!oc && !packet -> raw -> giaddr.s_addr) {
+               if (packet -> interface -> shared_network) {
+-                      shared_network_reference
+-                              (&packet -> shared_network,
+-                               packet -> interface -> shared_network, MDL);
+-                      return 1;
++                      struct in_addr any_addr;
++                      any_addr.s_addr = INADDR_ANY;
++
++                      if (!packet -> packet_type && memcmp(&packet -> raw -> ciaddr, &any_addr, 4)) {
++                              struct iaddr cip;
++                              memcpy(cip.iabuf, &packet -> raw -> ciaddr, 4);
++                              cip.len = 4;
++                              if (!find_grouped_subnet(&subnet, packet->interface->shared_network, cip, MDL))
++                                      norelay = 2;
++                      }
++
++                      if (!norelay) {
++                              shared_network_reference(&packet -> shared_network, packet -> interface -> shared_network, MDL);
++                              return 1;
++                      }
++              } else {
++                      return 0;
+               }
+-              return 0;
+       }
+       /* If there's an option indicating link connection, and it's valid,
+@@ -4228,7 +4241,10 @@ int locate_network (packet)
+               data_string_forget (&data, MDL);
+       } else {
+               ia.len = 4;
+-              memcpy (ia.iabuf, &packet -> raw -> giaddr, 4);
++              if (norelay)
++                      memcpy (ia.iabuf, &packet->raw->ciaddr, 4);
++              else
++                      memcpy (ia.iabuf, &packet->raw->giaddr, 4);
+       }
+       /* If we know the subnet on which the IP address lives, use it. */
+@@ -4236,7 +4252,10 @@ int locate_network (packet)
+               shared_network_reference (&packet -> shared_network,
+                                         subnet -> shared_network, MDL);
+               subnet_dereference (&subnet, MDL);
+-              return 1;
++              if (norelay)
++                      return norelay;
++              else
++                      return 1;
+       }
+       /* Otherwise, fail. */
diff --git a/src/patches/dhcp-4.2.1-64_bit_lease_parse.patch b/src/patches/dhcp-4.2.1-64_bit_lease_parse.patch
new file mode 100644 (file)
index 0000000..a540bc1
--- /dev/null
@@ -0,0 +1,94 @@
+diff -up dhcp-4.2.1b1/common/dispatch.c.64-bit_lease_parse dhcp-4.2.1b1/common/dispatch.c
+diff -up dhcp-4.2.1b1/common/parse.c.64-bit_lease_parse dhcp-4.2.1b1/common/parse.c
+--- dhcp-4.2.1b1/common/parse.c.64-bit_lease_parse     2010-12-30 00:01:42.000000000 +0100
++++ dhcp-4.2.1b1/common/parse.c        2011-01-28 08:01:10.000000000 +0100
+@@ -909,8 +909,8 @@ TIME 
+ parse_date_core(cfile)
+       struct parse *cfile;
+ {
+-      int guess;
+-      int tzoff, wday, year, mon, mday, hour, min, sec;
++      TIME guess;
++      long int tzoff, wday, year, mon, mday, hour, min, sec;
+       const char *val;
+       enum dhcp_token token;
+       static int months[11] = { 31, 59, 90, 120, 151, 181,
+@@ -936,7 +936,7 @@ parse_date_core(cfile)
+               }
+               token = next_token(&val, NULL, cfile); /* consume number */
+-              guess = atoi(val);
++              guess = atol(val);
+               return((TIME)guess);
+       }
+@@ -948,7 +948,7 @@ parse_date_core(cfile)
+               return((TIME)0);
+       }
+       token = next_token(&val, NULL, cfile); /* consume day of week */
+-      wday = atoi(val);
++      wday = atol(val);
+       /* Year... */
+       token = peek_token(&val, NULL, cfile);
+@@ -964,7 +964,7 @@ parse_date_core(cfile)
+          somebody invents a time machine, I think we can safely disregard
+          it.   This actually works around a stupid Y2K bug that was present
+          in a very early beta release of dhcpd. */
+-      year = atoi(val);
++      year = atol(val);
+       if (year > 1900)
+               year -= 1900;
+@@ -988,7 +988,7 @@ parse_date_core(cfile)
+               return((TIME)0);
+       }
+       token = next_token(&val, NULL, cfile); /* consume month */      
+-      mon = atoi(val) - 1;
++      mon = atol(val) - 1;
+       /* Slash separating month from day... */
+       token = peek_token(&val, NULL, cfile);
+@@ -1010,7 +1010,7 @@ parse_date_core(cfile)
+               return((TIME)0);
+       }
+       token = next_token(&val, NULL, cfile); /* consume day of month */
+-      mday = atoi(val);
++      mday = atol(val);
+       /* Hour... */
+       token = peek_token(&val, NULL, cfile);
+@@ -1021,7 +1021,7 @@ parse_date_core(cfile)
+               return((TIME)0);
+       }
+       token = next_token(&val, NULL, cfile); /* consume hour */
+-      hour = atoi(val);
++      hour = atol(val);
+       /* Colon separating hour from minute... */
+       token = peek_token(&val, NULL, cfile);
+@@ -1043,7 +1043,7 @@ parse_date_core(cfile)
+               return((TIME)0);
+       }
+       token = next_token(&val, NULL, cfile); /* consume minute */
+-      min = atoi(val);
++      min = atol(val);
+       /* Colon separating minute from second... */
+       token = peek_token(&val, NULL, cfile);
+@@ -1065,13 +1065,13 @@ parse_date_core(cfile)
+               return((TIME)0);
+       }
+       token = next_token(&val, NULL, cfile); /* consume second */
+-      sec = atoi(val);
++      sec = atol(val);
+       tzoff = 0;
+       token = peek_token(&val, NULL, cfile);
+       if (token == NUMBER) {
+               token = next_token(&val, NULL, cfile); /* consume tzoff */
+-              tzoff = atoi(val);
++              tzoff = atol(val);
+       } else if (token != SEMI) {
+               token = next_token(&val, NULL, cfile);
+               parse_warn(cfile,
diff --git a/src/patches/dhcp-4.2.1-invalid-dhclient-conf.patch b/src/patches/dhcp-4.2.1-invalid-dhclient-conf.patch
new file mode 100644 (file)
index 0000000..eeeea84
--- /dev/null
@@ -0,0 +1,12 @@
+diff -up dhcp-4.2.1b1/client/dhclient.conf.supersede dhcp-4.2.1b1/client/dhclient.conf
+--- dhcp-4.2.1b1/client/dhclient.conf.supersede        2010-09-15 01:03:56.000000000 +0200
++++ dhcp-4.2.1b1/client/dhclient.conf  2011-01-27 18:38:28.000000000 +0100
+@@ -4,7 +4,7 @@ send dhcp-lease-time 3600;
+ supersede domain-search "fugue.com", "home.vix.com";
+ prepend domain-name-servers 127.0.0.1;
+ request subnet-mask, broadcast-address, time-offset, routers,
+-      domain-name, domain-name-servers, host-name;
++      domain-search, domain-name-servers, host-name;
+ require subnet-mask, domain-name-servers;
+ timeout 60;
+ retry 60;
diff --git a/src/patches/dhcp-4.2.1-manpages.patch b/src/patches/dhcp-4.2.1-manpages.patch
new file mode 100644 (file)
index 0000000..9a42b7f
--- /dev/null
@@ -0,0 +1,264 @@
+diff -up dhcp-4.2.1b1/client/dhclient.8.man dhcp-4.2.1b1/client/dhclient.8
+--- dhcp-4.2.1b1/client/dhclient.8.man 2010-07-14 22:09:34.000000000 +0200
++++ dhcp-4.2.1b1/client/dhclient.8     2011-01-27 18:19:07.000000000 +0100
+@@ -115,6 +115,33 @@ dhclient - Dynamic Host Configuration Pr
+ .B -w
+ ]
+ [
++.B -B
++]
++[
++.B -I
++.I dhcp-client-identifier
++]
++[
++.B -H
++.I host-name
++]
++[
++.B -F
++.I fqdn.fqdn
++]
++[
++.B -V
++.I vendor-class-identifier
++]
++[
++.B -R
++.I request-option-list
++]
++[
++.B -timeout
++.I timeout
++]
++[
+ .B -v
+ ]
+ [
+@@ -264,6 +291,69 @@ not to exit when it doesn't find any suc
+ program can then be used to notify the client when a network interface
+ has been added or removed, so that the client can attempt to configure an IP
+ address on that interface.
++
++.TP
++.BI \-B
++Set the BOOTP broadcast flag in request packets so servers will always
++broadcast replies.
++
++.TP
++.BI \-I\ <dhcp-client-identifier>
++Specify the dhcp-client-identifier option to send to the DHCP server.
++
++.TP
++.BI \-H\ <host-name>
++Specify the host-name option to send to the DHCP server.  The host-name
++string only contains the client's hostname prefix, to which the server will
++append the ddns-domainname or domain-name options, if any, to derive the
++fully qualified domain name of the client.  The
++.B -H
++option cannot be used with the
++.B -F
++option.
++
++.TP
++.BI \-F\ <fqdn.fqdn>
++Specify the fqdn.fqdn option to send to the DHCP server.  This option cannot
++be used with the
++.B -H
++option.  The fqdn.fqdn option must specify the complete domain name of the
++client host, which the server may use for dynamic DNS updates.
++
++.TP
++.BI \-V\ <vendor-class-identifier>
++Specify the vendor-class-identifier option to send to the DHCP server.
++
++.TP
++.BI \-R\ <option>[,<option>...]
++Specify the list of options the client is to request from the server.  The
++option list must be a single string consisting of option names separated
++by at least one command and optional space characters.  The default option
++list is:
++
++.BR
++    subnet-mask, broadcast-address, time-offset, routers,
++.BR
++    domain-search, domain-name, domain-name-servers, host-name, 
++.BR
++    nis-domain, nis-servers, ntp-servers, interface-mtu
++
++.TP
++.B -R
++option does not append options to the default request, it overrides the
++default request list.  Keep this in mind if you want to request an
++additional option besides the default request list.  You will have to
++specify all option names for the
++.B -R
++parameter.
++
++.TP
++.BI \-timeout\ <timeout>
++Specify the time after which
++.B dhclient
++will decide that no DHCP servers can be contacted when no responses have been
++received.
++
+ .TP
+ .BI \-n
+ Do not configure any interfaces.  This is most likely to be useful in
+diff -up dhcp-4.2.1b1/client/dhclient.conf.5.man dhcp-4.2.1b1/client/dhclient.conf.5
+--- dhcp-4.2.1b1/client/dhclient.conf.5.man    2010-09-15 01:03:56.000000000 +0200
++++ dhcp-4.2.1b1/client/dhclient.conf.5        2011-01-27 18:22:56.000000000 +0100
+@@ -186,7 +186,8 @@ responding to the client send the client
+ options.   Only the option names should be specified in the request
+ statement - not option parameters.   By default, the DHCPv4 client
+ requests the subnet-mask, broadcast-address, time-offset, routers,
+-domain-name, domain-name-servers and host-name options while the DHCPv6
++domain-search, domain-name, domain-name-servers, host-name, nis-domain,
++nis-servers, ntp-servers and interface-mtu options while the DHCPv6
+ client requests the dhcp6 name-servers and domain-search options.  Note
+ that if you enter a \'request\' statement, you over-ride these defaults
+ and these options will not be requested.
+@@ -672,6 +673,17 @@ know the DHCP service(s) anycast MAC add
+ client.  The \fIlink-type\fR and \fImac-address\fR parameters are configured
+ in a similar manner to the \fBhardware\fR statement.
+ .PP
++ \fBbootp-broadcast-always;\fR
++.PP
++The
++.B bootp-broadcast-always
++statement instructs dhclient to always set the bootp broadcast flag in
++request packets, so that servers will always broadcast replies.
++This is equivalent to supplying the dhclient -B argument, and has
++the same effect as specifying 'always-broadcast' in the server's dhcpd.conf.
++This option is provided as an extension to enable dhclient to work
++on IBM s390 Linux guests.
++.PP
+ .SH SAMPLE
+ The following configuration file is used on a laptop running NetBSD
+ 1.3.   The laptop has an IP alias of 192.5.5.213, and has one
+@@ -697,7 +709,7 @@ interface "ep0" {
+     supersede domain-search "fugue.com", "rc.vix.com", "home.vix.com";
+     prepend domain-name-servers 127.0.0.1;
+     request subnet-mask, broadcast-address, time-offset, routers,
+-          domain-name, domain-name-servers, host-name;
++          domain-search, domain-name, domain-name-servers, host-name;
+     require subnet-mask, domain-name-servers;
+     script "CLIENTBINDIR/dhclient-script";
+     media "media 10baseT/UTP", "media 10base2/BNC";
+diff -up dhcp-4.2.1b1/client/dhclient-script.8.man dhcp-4.2.1b1/client/dhclient-script.8
+--- dhcp-4.2.1b1/client/dhclient-script.8.man  2010-07-06 21:03:11.000000000 +0200
++++ dhcp-4.2.1b1/client/dhclient-script.8      2011-01-27 18:24:44.000000000 +0100
+@@ -47,7 +47,7 @@ customizations are needed, they should b
+ exit hooks provided (see HOOKS for details).   These hooks will allow the
+ user to override the default behaviour of the client in creating a
+ .B /etc/resolv.conf
+-file.
++file, and to handle DHCP options not handled by default.
+ .PP
+ No standard client script exists for some operating systems, even though
+ the actual client may work, so a pioneering user may well need to create
+@@ -91,6 +91,26 @@ present.   The
+ .B ETCDIR/dhclient-exit-hooks
+ script can modify the valid of exit_status to change the exit status
+ of dhclient-script.
++.PP
++Immediately after dhclient brings an interface UP with a new IP address,
++subnet mask, and routes, in the REBOOT/BOUND states, it will check for the
++existence of an executable
++.B ETCDIR/dhclient-up-hooks
++script, and source it if found. This script can handle DHCP options in
++the environment that are not handled by default. A per-interface.
++.B ETCDIR/dhclient-${IF}-up-hooks
++script will override the generic script and be sourced when interface
++$IF has been brought up.
++.PP
++Immediately before dhclient brings an interface DOWN, removing its IP
++address, subnet mask, and routes, in the STOP/RELEASE  states, it will
++check for the existence of an executable
++.B ETCDIR/dhclient-down-hooks
++script, and source it if found. This script can handle DHCP options in
++the environment that are not handled by default. A per-interface
++.B ETCDIR/dhclient-${IF}-down-hooks
++script will override the generic script and be sourced when interface
++$IF is about to be brought down.
+ .SH OPERATION
+ When dhclient needs to invoke the client configuration script, it
+ defines a set of variables in the environment, and then invokes
+diff -up dhcp-4.2.1b1/common/dhcp-options.5.man dhcp-4.2.1b1/common/dhcp-options.5
+--- dhcp-4.2.1b1/common/dhcp-options.5.man     2010-07-13 22:56:56.000000000 +0200
++++ dhcp-4.2.1b1/common/dhcp-options.5 2011-01-27 18:25:57.000000000 +0100
+@@ -913,6 +913,21 @@ classless IP routing - it does not inclu
+ classless IP routing is now the most widely deployed routing standard,
+ this option is virtually useless, and is not implemented by any of the
+ popular DHCP clients, for example the Microsoft DHCP client.
++.PP
++NOTE to Fedora dhclient users:
++.br
++dhclient-script interprets trailing 0 octets of the target as indicating
++the subnet class of the route, so for the following static-routes value:
++.br
++        option static-routes 172.0.0.0 172.16.2.254,
++.br
++                             192.168.0.0 192.168.2.254;
++.br
++dhclient-script will create routes:
++.br
++        172/8 via 172.16.2.254 dev $interface
++.br
++        192.168/16 via 192.168.2.254 dev $interface
+ .RE
+ .PP
+ .nf
+diff -up dhcp-4.2.1b1/server/dhcpd.conf.5.man dhcp-4.2.1b1/server/dhcpd.conf.5
+--- dhcp-4.2.1b1/server/dhcpd.conf.5.man       2010-07-06 21:03:12.000000000 +0200
++++ dhcp-4.2.1b1/server/dhcpd.conf.5   2011-01-27 18:29:12.000000000 +0100
+@@ -519,6 +519,9 @@ pool {
+ };
+ .fi
+ .PP
++Dynamic BOOTP leases are not compatible with failover, and, as such,
++you need to disallow BOOTP in pools that you are using failover for.
++.PP
+ The  server currently  does very  little  sanity checking,  so if  you
+ configure it wrong, it will just  fail in odd ways.  I would recommend
+ therefore that you either do  failover or don't do failover, but don't
+@@ -533,9 +536,9 @@ primary server might look like this:
+ failover peer "foo" {
+   primary;
+   address anthrax.rc.vix.com;
+-  port 519;
++  port 647;
+   peer address trantor.rc.vix.com;
+-  peer port 520;
++  peer port 847;
+   max-response-delay 60;
+   max-unacked-updates 10;
+   mclt 3600;
+@@ -1305,7 +1308,7 @@ the zone containing PTR records - for IS
+ .PP
+ .nf
+ key DHCP_UPDATER {
+-  algorithm HMAC-MD5.SIG-ALG.REG.INT;
++  algorithm hmac-md5;
+   secret pRP5FapFoJ95JEL06sv4PQ==;
+ };
+@@ -1328,7 +1331,7 @@ dhcpd.conf file:
+ .PP
+ .nf
+ key DHCP_UPDATER {
+-  algorithm HMAC-MD5.SIG-ALG.REG.INT;
++  algorithm hmac-md5;
+   secret pRP5FapFoJ95JEL06sv4PQ==;
+ };
+@@ -2540,7 +2543,8 @@ statement
+ The \fInext-server\fR statement is used to specify the host address of
+ the server from which the initial boot file (specified in the
+ \fIfilename\fR statement) is to be loaded.   \fIServer-name\fR should
+-be a numeric IP address or a domain name.
++be a numeric IP address or a domain name.  If no \fInext-server\fR statement
++applies to a given client, the address 0.0.0.0 is used.
+ .RE
+ .PP
+ The
diff --git a/src/patches/dhcp-4.2.1-retransmission.patch b/src/patches/dhcp-4.2.1-retransmission.patch
new file mode 100644 (file)
index 0000000..18e447f
--- /dev/null
@@ -0,0 +1,48 @@
+diff -up dhcp-4.2.1b1/client/dhc6.c.retransmission dhcp-4.2.1b1/client/dhc6.c
+--- dhcp-4.2.1b1/client/dhc6.c.retransmission  2011-01-28 08:40:56.000000000 +0100
++++ dhcp-4.2.1b1/client/dhc6.c 2011-01-28 08:39:22.000000000 +0100
+@@ -361,7 +361,7 @@ dhc6_retrans_init(struct client_state *c
+ static void
+ dhc6_retrans_advance(struct client_state *client)
+ {
+-      struct timeval elapsed;
++      struct timeval elapsed, elapsed_after_RT;
+       /* elapsed = cur - start */
+       elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
+@@ -378,6 +378,8 @@ dhc6_retrans_advance(struct client_state
+               elapsed.tv_sec += 1;
+               elapsed.tv_usec -= 1000000;
+       }
++      elapsed_after_RT.tv_sec = elapsed.tv_sec;
++      elapsed_after_RT.tv_usec = elapsed.tv_usec;
+       /*
+        * RT for each subsequent message transmission is based on the previous
+@@ -415,13 +417,10 @@ dhc6_retrans_advance(struct client_state
+               elapsed.tv_usec -= 1000000;
+       }
+       if (elapsed.tv_sec >= client->MRD) {
+-              /*
+-               * wake at RT + cur = start + MRD
+-               */
+-              client->RT = client->MRD +
+-                      (client->start_time.tv_sec - cur_tv.tv_sec);
+-              client->RT = client->RT * 100 +
+-                      (client->start_time.tv_usec - cur_tv.tv_usec) / 10000;
++              client->RT = client->MRD - elapsed_after_RT.tv_sec;
++              client->RT = client->RT * 100 - elapsed_after_RT.tv_usec / 10000;
++              if (client->RT < 0)
++                      client->RT = 0;
+       }
+       client->txcount++;
+ }
+@@ -1497,7 +1496,7 @@ check_timing6 (struct client_state *clie
+       }
+       /* Check if finished (-1 argument). */
+-      if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
++      if ((client->MRD != 0) && (elapsed.tv_sec >= client->MRD)) {
+               log_info("Max retransmission duration exceeded.");
+               return(CHK_TIM_MRD_EXCEEDED);
+       }
diff --git a/src/patches/dhcp-4.2.1-sendDecline.patch b/src/patches/dhcp-4.2.1-sendDecline.patch
new file mode 100644 (file)
index 0000000..b2fa4af
--- /dev/null
@@ -0,0 +1,231 @@
+diff -up dhcp-4.2.1-P1/client/dhc6.c.sendDecline dhcp-4.2.1-P1/client/dhc6.c
+--- dhcp-4.2.1-P1/client/dhc6.c.sendDecline    2010-09-10 22:27:11.000000000 +0200
++++ dhcp-4.2.1-P1/client/dhc6.c        2011-06-17 14:19:48.992099868 +0200
+@@ -95,6 +95,8 @@ void do_select6(void *input);
+ void do_refresh6(void *input);
+ static void do_release6(void *input);
+ static void start_bound(struct client_state *client);
++static void start_decline6(struct client_state *client);
++static void do_decline6(void *input);
+ static void start_informed(struct client_state *client);
+ void informed_handler(struct packet *packet, struct client_state *client);
+ void bound_handler(struct packet *packet, struct client_state *client);
+@@ -2075,6 +2077,7 @@ start_release6(struct client_state *clie
+       cancel_timeout(do_select6, client);
+       cancel_timeout(do_refresh6, client);
+       cancel_timeout(do_release6, client);
++      cancel_timeout(do_decline6, client);
+       client->state = S_STOPPED;
+       /*
+@@ -2708,6 +2711,7 @@ dhc6_check_reply(struct client_state *cl
+               break;
+             case S_STOPPED:
++            case S_DECLINED:
+               action = dhc6_stop_action;
+               break;
+@@ -2809,6 +2813,7 @@ dhc6_check_reply(struct client_state *cl
+               break;
+             case S_STOPPED:
++            case S_DECLINED:
+               /* Nothing critical to do at this stage. */
+               break;
+@@ -3799,17 +3804,23 @@ reply_handler(struct packet *packet, str
+       cancel_timeout(do_select6, client);
+       cancel_timeout(do_refresh6, client);
+       cancel_timeout(do_release6, client);
++      cancel_timeout(do_decline6, client);
+       /* If this is in response to a Release/Decline, clean up and return. */
+-      if (client->state == S_STOPPED) {
+-              if (client->active_lease == NULL)
+-                      return;
++      if ((client->state == S_STOPPED) ||
++          (client->state == S_DECLINED)) {
++
++              if (client->active_lease != NULL) {
++                      dhc6_lease_destroy(&client->active_lease, MDL);
++                      client->active_lease = NULL;
++                      /* We should never wait for nothing!? */
++                      if (stopping_finished())
++                              exit(0);
++              }
++
++              if (client->state == S_DECLINED)
++                      start_init6(client);
+-              dhc6_lease_destroy(&client->active_lease, MDL);
+-              client->active_lease = NULL;
+-              /* We should never wait for nothing!? */
+-              if (stopping_finished())
+-                      exit(0);
+               return;
+       }
+@@ -4336,7 +4347,11 @@ start_bound(struct client_state *client)
+                                                    oldia, oldaddr);
+                       dhc6_marshall_values("new_", client, lease, ia, addr);
+-                      script_go(client);
++                      // when script returns 3, DAD failed
++                      if (script_go(client) == 3) {
++                              start_decline6(client);
++                              return;
++                      }
+               }
+               /* XXX: maybe we should loop on the old values instead? */
+@@ -4382,6 +4397,149 @@ start_bound(struct client_state *client)
+       dhc6_check_times(client);
+ }
++/*
++ * Decline addresses.
++ */
++void
++start_decline6(struct client_state *client)
++{
++      /* Cancel any pending transmissions */
++      cancel_timeout(do_confirm6, client);
++      cancel_timeout(do_select6, client);
++      cancel_timeout(do_refresh6, client);
++      cancel_timeout(do_release6, client);
++      cancel_timeout(do_decline6, client);
++      client->state = S_DECLINED;
++
++      if (client->active_lease == NULL)
++              return;
++
++      /* Set timers per RFC3315 section 18.1.7. */
++      client->IRT = DEC_TIMEOUT * 100;
++      client->MRT = 0;
++      client->MRC = DEC_MAX_RC;
++      client->MRD = 0;
++
++      dhc6_retrans_init(client);
++      client->v6_handler = reply_handler;
++
++      client->refresh_type = DHCPV6_DECLINE;
++      do_decline6(client);
++}
++
++/*
++ * do_decline6() creates a Decline packet and transmits it.
++ */
++static void
++do_decline6(void *input)
++{
++      struct client_state *client;
++      struct data_string ds;
++      int send_ret;
++      struct timeval elapsed, tv;
++
++      client = input;
++
++      if ((client->active_lease == NULL) || !active_prefix(client))
++              return;
++
++      if ((client->MRC != 0) && (client->txcount > client->MRC))  {
++              log_info("Max retransmission count exceeded.");
++              goto decline_done;
++      }
++
++      /*
++       * Start_time starts at the first transmission.
++       */
++      if (client->txcount == 0) {
++              client->start_time.tv_sec = cur_tv.tv_sec;
++              client->start_time.tv_usec = cur_tv.tv_usec;
++      }
++
++      /* elapsed = cur - start */
++      elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
++      elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
++      if (elapsed.tv_usec < 0) {
++              elapsed.tv_sec -= 1;
++              elapsed.tv_usec += 1000000;
++      }
++
++      memset(&ds, 0, sizeof(ds));
++      if (!buffer_allocate(&ds.buffer, 4, MDL)) {
++              log_error("Unable to allocate memory for Decline.");
++              goto decline_done;
++      }
++
++      ds.data = ds.buffer->data;
++      ds.len = 4;
++      ds.buffer->data[0] = DHCPV6_DECLINE;
++      memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
++
++      /* Form an elapsed option. */
++      /* Maximum value is 65535 1/100s coded as 0xffff. */
++      if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
++          ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
++              client->elapsed = 0xffff;
++      } else {
++              client->elapsed = elapsed.tv_sec * 100;
++              client->elapsed += elapsed.tv_usec / 10000;
++      }
++
++      client->elapsed = htons(client->elapsed);
++
++      log_debug("XMT: Forming Decline.");
++      make_client6_options(client, &client->sent_options,
++                           client->active_lease, DHCPV6_DECLINE);
++      dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
++                                  client->sent_options, &global_scope,
++                                  &dhcpv6_universe);
++
++      /* Append IA's (but don't release temporary addresses). */
++      if (wanted_ia_na &&
++          dhc6_add_ia_na(client, &ds, client->active_lease,
++                         DHCPV6_DECLINE) != ISC_R_SUCCESS) {
++              data_string_forget(&ds, MDL);
++              goto decline_done;
++      }
++      if (wanted_ia_pd &&
++          dhc6_add_ia_pd(client, &ds, client->active_lease,
++                         DHCPV6_DECLINE) != ISC_R_SUCCESS) {
++              data_string_forget(&ds, MDL);
++              goto decline_done;
++      }
++
++      /* Transmit and wait. */
++      log_info("XMT: Decline on %s, interval %ld0ms.",
++               client->name ? client->name : client->interface->name,
++               (long int)client->RT);
++
++      send_ret = send_packet6(client->interface, ds.data, ds.len,
++                              &DHCPv6DestAddr);
++      if (send_ret != ds.len) {
++              log_error("dhc6: sendpacket6() sent %d of %d bytes",
++                        send_ret, ds.len);
++      }
++
++      data_string_forget(&ds, MDL);
++
++      /* Wait RT */
++      tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
++      tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
++      if (tv.tv_usec >= 1000000) {
++              tv.tv_sec += 1;
++              tv.tv_usec -= 1000000;
++      }
++      add_timeout(&tv, do_decline6, client, NULL, NULL);
++      dhc6_retrans_advance(client);
++      return;
++
++decline_done:
++      dhc6_lease_destroy(&client->active_lease, MDL);
++      client->active_lease = NULL;
++      start_init6(client);
++      return;
++}
++
+ /* While bound, ignore packets.  In the future we'll want to answer
+  * Reconfigure-Request messages and the like.
+  */
diff --git a/src/patches/dhcp-4.2.2-CLOEXEC.patch b/src/patches/dhcp-4.2.2-CLOEXEC.patch
new file mode 100644 (file)
index 0000000..b07e2ff
--- /dev/null
@@ -0,0 +1,423 @@
+diff -up dhcp-4.2.2b1/client/clparse.c.cloexec dhcp-4.2.2b1/client/clparse.c
+--- dhcp-4.2.2b1/client/clparse.c.cloexec      2011-07-01 14:13:30.973887714 +0200
++++ dhcp-4.2.2b1/client/clparse.c      2011-07-01 14:15:15.021580693 +0200
+@@ -246,7 +246,7 @@ int read_client_conf_file (const char *n
+       int token;
+       isc_result_t status;
+-      if ((file = open (name, O_RDONLY)) < 0)
++      if ((file = open (name, O_RDONLY | O_CLOEXEC)) < 0)
+               return uerr2isc (errno);
+       cfile = NULL;
+@@ -283,7 +283,7 @@ void read_client_leases ()
+       /* Open the lease file.   If we can't open it, just return -
+          we can safely trust the server to remember our state. */
+-      if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
++      if ((file = open (path_dhclient_db, O_RDONLY | O_CLOEXEC)) < 0)
+               return;
+       cfile = NULL;
+diff -up dhcp-4.2.2b1/client/dhclient.c.cloexec dhcp-4.2.2b1/client/dhclient.c
+--- dhcp-4.2.2b1/client/dhclient.c.cloexec     2011-07-01 14:13:30.970887717 +0200
++++ dhcp-4.2.2b1/client/dhclient.c     2011-07-01 14:16:51.485930388 +0200
+@@ -148,11 +148,11 @@ main(int argc, char **argv) {
+       /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
+          2 (stderr) are open. To do this, we assume that when we
+          open a file the lowest available file descriptor is used. */
+-      fd = open("/dev/null", O_RDWR);
++      fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+       if (fd == 0)
+-              fd = open("/dev/null", O_RDWR);
++              fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+       if (fd == 1)
+-              fd = open("/dev/null", O_RDWR);
++              fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+       if (fd == 2)
+               log_perror = 0; /* No sense logging to /dev/null. */
+       else if (fd != -1)
+@@ -506,7 +506,7 @@ main(int argc, char **argv) {
+               int e;
+               oldpid = 0;
+-              if ((pidfd = fopen(path_dhclient_pid, "r")) != NULL) {
++              if ((pidfd = fopen(path_dhclient_pid, "re")) != NULL) {
+                       e = fscanf(pidfd, "%ld\n", &temp);
+                       oldpid = (pid_t)temp;
+@@ -548,7 +548,7 @@ main(int argc, char **argv) {
+                                       strncpy(new_path_dhclient_pid, path_dhclient_pid, pfx);
+                                       sprintf(new_path_dhclient_pid + pfx, "-%s.pid", ip->name);
+-                                      if ((pidfd = fopen(new_path_dhclient_pid, "r")) != NULL) {
++                                      if ((pidfd = fopen(new_path_dhclient_pid, "re")) != NULL) {
+                                               e = fscanf(pidfd, "%ld\n", &temp);
+                                               oldpid = (pid_t)temp;
+@@ -573,7 +573,7 @@ main(int argc, char **argv) {
+               int dhc_running = 0;
+               char procfn[256] = "";
+-              if ((pidfp = fopen(path_dhclient_pid, "r")) != NULL) {
++              if ((pidfp = fopen(path_dhclient_pid, "re")) != NULL) {
+                       if ((fscanf(pidfp, "%ld", &temp)==1) && ((dhcpid=(pid_t)temp) > 0)) {
+                               snprintf(procfn,256,"/proc/%u",dhcpid);
+                               dhc_running = (access(procfn, F_OK) == 0);
+@@ -2995,7 +2995,7 @@ void rewrite_client_leases ()
+       if (leaseFile != NULL)
+               fclose (leaseFile);
+-      leaseFile = fopen (path_dhclient_db, "w");
++      leaseFile = fopen (path_dhclient_db, "we");
+       if (leaseFile == NULL) {
+               log_error ("can't create %s: %m", path_dhclient_db);
+               return;
+@@ -3105,7 +3105,7 @@ write_duid(struct data_string *duid)
+               return DHCP_R_INVALIDARG;
+       if (leaseFile == NULL) {        /* XXX? */
+-              leaseFile = fopen(path_dhclient_db, "w");
++              leaseFile = fopen(path_dhclient_db, "we");
+               if (leaseFile == NULL) {
+                       log_error("can't create %s: %m", path_dhclient_db);
+                       return ISC_R_IOERROR;
+@@ -3285,7 +3285,7 @@ int write_client_lease (client, lease, r
+               return 1;
+       if (leaseFile == NULL) {        /* XXX */
+-              leaseFile = fopen (path_dhclient_db, "w");
++              leaseFile = fopen (path_dhclient_db, "we");
+               if (leaseFile == NULL) {
+                       log_error ("can't create %s: %m", path_dhclient_db);
+                       return 0;
+@@ -3772,9 +3772,9 @@ void go_daemon ()
+       close(2);
+       /* Reopen them on /dev/null. */
+-      open("/dev/null", O_RDWR);
+-      open("/dev/null", O_RDWR);
+-      open("/dev/null", O_RDWR);
++      open("/dev/null", O_RDWR | O_CLOEXEC);
++      open("/dev/null", O_RDWR | O_CLOEXEC);
++      open("/dev/null", O_RDWR | O_CLOEXEC);
+       write_client_pid_file ();
+@@ -3791,14 +3791,14 @@ void write_client_pid_file ()
+               return;
+       }
+-      pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644);
++      pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644);
+       if (pfdesc < 0) {
+               log_error ("Can't create %s: %m", path_dhclient_pid);
+               return;
+       }
+-      pf = fdopen (pfdesc, "w");
++      pf = fdopen (pfdesc, "we");
+       if (!pf) {
+               close(pfdesc);
+               log_error ("Can't fdopen %s: %m", path_dhclient_pid);
+diff -up dhcp-4.2.2b1/common/bpf.c.cloexec dhcp-4.2.2b1/common/bpf.c
+--- dhcp-4.2.2b1/common/bpf.c.cloexec  2011-07-01 14:13:30.976887712 +0200
++++ dhcp-4.2.2b1/common/bpf.c  2011-07-01 14:13:31.030887673 +0200
+@@ -94,7 +94,7 @@ int if_register_bpf (info)
+       for (b = 0; 1; b++) {
+               /* %Audit% 31 bytes max. %2004.06.17,Safe% */
+               sprintf(filename, BPF_FORMAT, b);
+-              sock = open (filename, O_RDWR, 0);
++              sock = open (filename, O_RDWR | O_CLOEXEC, 0);
+               if (sock < 0) {
+                       if (errno == EBUSY) {
+                               continue;
+diff -up dhcp-4.2.2b1/common/discover.c.cloexec dhcp-4.2.2b1/common/discover.c
+--- dhcp-4.2.2b1/common/discover.c.cloexec     2011-06-27 18:18:20.000000000 +0200
++++ dhcp-4.2.2b1/common/discover.c     2011-07-01 14:13:31.031887673 +0200
+@@ -421,7 +421,7 @@ begin_iface_scan(struct iface_conf_list 
+       int len;
+       int i;
+-      ifaces->fp = fopen("/proc/net/dev", "r");
++      ifaces->fp = fopen("/proc/net/dev", "re");
+       if (ifaces->fp == NULL) {
+               log_error("Error opening '/proc/net/dev' to list interfaces");
+               return 0;
+@@ -456,7 +456,7 @@ begin_iface_scan(struct iface_conf_list 
+ #ifdef DHCPv6
+       if (local_family == AF_INET6) {
+-              ifaces->fp6 = fopen("/proc/net/if_inet6", "r");
++              ifaces->fp6 = fopen("/proc/net/if_inet6", "re");
+               if (ifaces->fp6 == NULL) {
+                       log_error("Error opening '/proc/net/if_inet6' to "
+                                 "list IPv6 interfaces; %m");
+diff -up dhcp-4.2.2b1/common/dlpi.c.cloexec dhcp-4.2.2b1/common/dlpi.c
+--- dhcp-4.2.2b1/common/dlpi.c.cloexec 2011-07-01 14:13:30.977887712 +0200
++++ dhcp-4.2.2b1/common/dlpi.c 2011-07-01 14:13:31.032887673 +0200
+@@ -806,7 +806,7 @@ dlpiopen(const char *ifname) {
+       }
+       *dp = '\0';
+       
+-      return open (devname, O_RDWR, 0);
++      return open (devname, O_RDWR | O_CLOEXEC, 0);
+ }
+ /*
+diff -up dhcp-4.2.2b1/common/nit.c.cloexec dhcp-4.2.2b1/common/nit.c
+--- dhcp-4.2.2b1/common/nit.c.cloexec  2011-07-01 14:13:30.978887712 +0200
++++ dhcp-4.2.2b1/common/nit.c  2011-07-01 14:13:31.033887672 +0200
+@@ -81,7 +81,7 @@ int if_register_nit (info)
+       struct strioctl sio;
+       /* Open a NIT device */
+-      sock = open ("/dev/nit", O_RDWR);
++      sock = open ("/dev/nit", O_RDWR | O_CLOEXEC);
+       if (sock < 0)
+               log_fatal ("Can't open NIT device for %s: %m", info -> name);
+diff -up dhcp-4.2.2b1/common/resolv.c.cloexec dhcp-4.2.2b1/common/resolv.c
+--- dhcp-4.2.2b1/common/resolv.c.cloexec       2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/common/resolv.c       2011-07-01 14:13:31.033887672 +0200
+@@ -49,7 +49,7 @@ void read_resolv_conf (parse_time)
+       struct domain_search_list *dp, *dl, *nd;
+       isc_result_t status;
+-      if ((file = open (path_resolv_conf, O_RDONLY)) < 0) {
++      if ((file = open (path_resolv_conf, O_RDONLY | O_CLOEXEC)) < 0) {
+               log_error ("Can't open %s: %m", path_resolv_conf);
+               return;
+       }
+diff -up dhcp-4.2.2b1/common/upf.c.cloexec dhcp-4.2.2b1/common/upf.c
+--- dhcp-4.2.2b1/common/upf.c.cloexec  2011-07-01 14:13:30.979887712 +0200
++++ dhcp-4.2.2b1/common/upf.c  2011-07-01 14:13:31.034887671 +0200
+@@ -77,7 +77,7 @@ int if_register_upf (info)
+               /* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */
+               sprintf(filename, "/dev/pf/pfilt%d", b);
+-              sock = open (filename, O_RDWR, 0);
++              sock = open (filename, O_RDWR | O_CLOEXEC, 0);
+               if (sock < 0) {
+                       if (errno == EBUSY) {
+                               continue;
+diff -up dhcp-4.2.2b1/dst/dst_api.c.cloexec dhcp-4.2.2b1/dst/dst_api.c
+--- dhcp-4.2.2b1/dst/dst_api.c.cloexec 2009-10-29 01:46:48.000000000 +0100
++++ dhcp-4.2.2b1/dst/dst_api.c 2011-07-01 14:13:31.035887670 +0200
+@@ -437,7 +437,7 @@ dst_s_write_private_key(const DST_KEY *k
+                            PRIVATE_KEY, PATH_MAX);
+       /* Do not overwrite an existing file */
+-      if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) {
++      if ((fp = dst_s_fopen(file, "we", 0600)) != NULL) {
+               int nn;
+               if ((nn = fwrite(encoded_block, 1, len, fp)) != len) {
+                       EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n",
+@@ -494,7 +494,7 @@ dst_s_read_public_key(const char *in_nam
+        * flags, proto, alg stored as decimal (or hex numbers FIXME).
+        * (FIXME: handle parentheses for line continuation.)
+        */
+-      if ((fp = dst_s_fopen(name, "r", 0)) == NULL) {
++      if ((fp = dst_s_fopen(name, "re", 0)) == NULL) {
+               EREPORT(("dst_read_public_key(): Public Key not found %s\n",
+                        name));
+               return (NULL);
+@@ -620,7 +620,7 @@ dst_s_write_public_key(const DST_KEY *ke
+               return (0);
+       }
+       /* create public key file */
+-      if ((fp = dst_s_fopen(filename, "w+", 0644)) == NULL) {
++      if ((fp = dst_s_fopen(filename, "w+e", 0644)) == NULL) {
+               EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n",
+                        filename, errno));
+               return (0);
+@@ -854,7 +854,7 @@ dst_s_read_private_key_file(char *name, 
+               return (0);
+       }
+       /* first check if we can find the key file */
+-      if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) {
++      if ((fp = dst_s_fopen(filename, "re", 0)) == NULL) {
+               EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n",
+                        filename, dst_path[0] ? dst_path :
+                        (char *) getcwd(NULL, PATH_MAX - 1)));
+diff -up dhcp-4.2.2b1/dst/prandom.c.cloexec dhcp-4.2.2b1/dst/prandom.c
+--- dhcp-4.2.2b1/dst/prandom.c.cloexec 2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/dst/prandom.c 2011-07-01 14:13:31.035887670 +0200
+@@ -269,7 +269,7 @@ get_dev_random(u_char *output, unsigned 
+       s = stat("/dev/random", &st);
+       if (s == 0 && S_ISCHR(st.st_mode)) {
+-              if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) != -1) {
++              if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK | O_CLOEXEC)) != -1) {
+                       if ((n = read(fd, output, size)) < 0)
+                               n = 0;
+                       close(fd);
+@@ -480,7 +480,7 @@ digest_file(dst_work *work) 
+               work->file_digest = dst_free_key(work->file_digest);
+               return (0);
+       }
+-      if ((fp = fopen(name, "r")) == NULL) 
++      if ((fp = fopen(name, "re")) == NULL) 
+               return (0);
+       for (no = 0; (i = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0; 
+            no += i) 
+diff -up dhcp-4.2.2b1/omapip/trace.c.cloexec dhcp-4.2.2b1/omapip/trace.c
+--- dhcp-4.2.2b1/omapip/trace.c.cloexec        2010-05-27 02:34:57.000000000 +0200
++++ dhcp-4.2.2b1/omapip/trace.c        2011-07-01 14:13:31.036887669 +0200
+@@ -141,10 +141,10 @@ isc_result_t trace_begin (const char *fi
+               return DHCP_R_INVALIDARG;
+       }
+-      traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL, 0600);
++      traceoutfile = open (filename, O_CREAT | O_WRONLY | O_EXCL | O_CLOEXEC, 0600);
+       if (traceoutfile < 0 && errno == EEXIST) {
+               log_error ("WARNING: Overwriting trace file \"%s\"", filename);
+-              traceoutfile = open (filename, O_WRONLY | O_EXCL | O_TRUNC,
++              traceoutfile = open (filename, O_WRONLY | O_EXCL | O_TRUNC | O_CLOEXEC,
+                                    0600);
+       }
+@@ -431,7 +431,7 @@ void trace_file_replay (const char *file
+       isc_result_t result;
+       int len;
+-      traceinfile = fopen (filename, "r");
++      traceinfile = fopen (filename, "re");
+       if (!traceinfile) {
+               log_error("Can't open tracefile %s: %m", filename);
+               return;
+diff -up dhcp-4.2.2b1/relay/dhcrelay.c.cloexec dhcp-4.2.2b1/relay/dhcrelay.c
+--- dhcp-4.2.2b1/relay/dhcrelay.c.cloexec      2011-05-10 15:07:37.000000000 +0200
++++ dhcp-4.2.2b1/relay/dhcrelay.c      2011-07-01 14:18:07.630209767 +0200
+@@ -183,11 +183,11 @@ main(int argc, char **argv) {
+       /* Make sure that file descriptors 0(stdin), 1,(stdout), and
+          2(stderr) are open. To do this, we assume that when we
+          open a file the lowest available file descriptor is used. */
+-      fd = open("/dev/null", O_RDWR);
++      fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+       if (fd == 0)
+-              fd = open("/dev/null", O_RDWR);
++              fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+       if (fd == 1)
+-              fd = open("/dev/null", O_RDWR);
++              fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+       if (fd == 2)
+               log_perror = 0; /* No sense logging to /dev/null. */
+       else if (fd != -1)
+@@ -540,13 +540,13 @@ main(int argc, char **argv) {
+               if (no_pid_file == ISC_FALSE) {
+                       pfdesc = open(path_dhcrelay_pid,
+-                                    O_CREAT | O_TRUNC | O_WRONLY, 0644);
++                                    O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644);
+                       if (pfdesc < 0) {
+                               log_error("Can't create %s: %m",
+                                         path_dhcrelay_pid);
+                       } else {
+-                              pf = fdopen(pfdesc, "w");
++                              pf = fdopen(pfdesc, "we");
+                               if (!pf)
+                                       log_error("Can't fdopen %s: %m",
+                                                 path_dhcrelay_pid);
+diff -up dhcp-4.2.2b1/server/confpars.c.cloexec dhcp-4.2.2b1/server/confpars.c
+--- dhcp-4.2.2b1/server/confpars.c.cloexec     2010-10-14 00:34:45.000000000 +0200
++++ dhcp-4.2.2b1/server/confpars.c     2011-07-01 14:13:31.039887666 +0200
+@@ -116,7 +116,7 @@ isc_result_t read_conf_file (const char 
+       }
+ #endif
+-      if ((file = open (filename, O_RDONLY)) < 0) {
++      if ((file = open (filename, O_RDONLY | O_CLOEXEC)) < 0) {
+               if (leasep) {
+                       log_error ("Can't open lease database %s: %m --",
+                                  path_dhcpd_db);
+diff -up dhcp-4.2.2b1/server/db.c.cloexec dhcp-4.2.2b1/server/db.c
+--- dhcp-4.2.2b1/server/db.c.cloexec   2010-09-14 00:15:26.000000000 +0200
++++ dhcp-4.2.2b1/server/db.c   2011-07-01 14:13:31.040887665 +0200
+@@ -1035,7 +1035,7 @@ void db_startup (testp)
+       }
+ #endif
+       if (!testp) {
+-              db_file = fopen (path_dhcpd_db, "a");
++              db_file = fopen (path_dhcpd_db, "ae");
+               if (!db_file)
+                       log_fatal ("Can't open %s for append.", path_dhcpd_db);
+               expire_all_pools ();
+@@ -1083,12 +1083,12 @@ int new_lease_file ()
+                    path_dhcpd_db, (int)t) >= sizeof newfname)
+               log_fatal("new_lease_file: lease file path too long");
+-      db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT, 0664);
++      db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0664);
+       if (db_fd < 0) {
+               log_error ("Can't create new lease file: %m");
+               return 0;
+       }
+-      if ((new_db_file = fdopen(db_fd, "w")) == NULL) {
++      if ((new_db_file = fdopen(db_fd, "we")) == NULL) {
+               log_error("Can't fdopen new lease file: %m");
+               close(db_fd);
+               goto fdfail;
+diff -up dhcp-4.2.2b1/server/dhcpd.c.cloexec dhcp-4.2.2b1/server/dhcpd.c
+--- dhcp-4.2.2b1/server/dhcpd.c.cloexec        2011-04-21 16:08:15.000000000 +0200
++++ dhcp-4.2.2b1/server/dhcpd.c        2011-07-01 14:19:40.354124505 +0200
+@@ -270,11 +270,11 @@ main(int argc, char **argv) {
+         /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
+            2 (stderr) are open. To do this, we assume that when we
+            open a file the lowest available file descriptor is used. */
+-        fd = open("/dev/null", O_RDWR);
++        fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+         if (fd == 0)
+-                fd = open("/dev/null", O_RDWR);
++                fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+         if (fd == 1)
+-                fd = open("/dev/null", O_RDWR);
++                fd = open("/dev/null", O_RDWR | O_CLOEXEC);
+         if (fd == 2)
+                 log_perror = 0; /* No sense logging to /dev/null. */
+         else if (fd != -1)
+@@ -793,7 +793,7 @@ main(int argc, char **argv) {
+        */
+       if (no_pid_file == ISC_FALSE) {
+               /*Read previous pid file. */
+-              if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
++              if ((i = open (path_dhcpd_pid, O_RDONLY | O_CLOEXEC)) >= 0) {
+                       status = read(i, pbuf, (sizeof pbuf) - 1);
+                       close (i);
+                       if (status > 0) {
+@@ -812,7 +812,7 @@ main(int argc, char **argv) {
+               }
+               /* Write new pid file. */
+-              i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644);
++              i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
+               if (i >= 0) {
+                       sprintf(pbuf, "%d\n", (int) getpid());
+                       IGNORE_RET (write(i, pbuf, strlen(pbuf)));
+@@ -840,9 +840,9 @@ main(int argc, char **argv) {
+                 close(2);
+                 /* Reopen them on /dev/null. */
+-                open("/dev/null", O_RDWR);
+-                open("/dev/null", O_RDWR);
+-                open("/dev/null", O_RDWR);
++                open("/dev/null", O_RDWR | O_CLOEXEC);
++                open("/dev/null", O_RDWR | O_CLOEXEC);
++                open("/dev/null", O_RDWR | O_CLOEXEC);
+                 log_perror = 0; /* No sense logging to /dev/null. */
+                       IGNORE_RET (chdir("/"));
+diff -up dhcp-4.2.2b1/server/ldap.c.cloexec dhcp-4.2.2b1/server/ldap.c
+--- dhcp-4.2.2b1/server/ldap.c.cloexec 2010-03-25 16:26:58.000000000 +0100
++++ dhcp-4.2.2b1/server/ldap.c 2011-07-01 14:13:31.043887665 +0200
+@@ -685,7 +685,7 @@ ldap_start (void)
+   if (ldap_debug_file != NULL && ldap_debug_fd == -1)
+     {
+-      if ((ldap_debug_fd = open (ldap_debug_file, O_CREAT | O_TRUNC | O_WRONLY,
++      if ((ldap_debug_fd = open (ldap_debug_file, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
+                                  S_IRUSR | S_IWUSR)) < 0)
+         log_error ("Error opening debug LDAP log file %s: %s", ldap_debug_file,
+                    strerror (errno));
diff --git a/src/patches/dhcp-4.2.2-capability.patch b/src/patches/dhcp-4.2.2-capability.patch
new file mode 100644 (file)
index 0000000..79af036
--- /dev/null
@@ -0,0 +1,323 @@
+diff -up dhcp-4.2.2b1/client/dhclient.8.capability dhcp-4.2.2b1/client/dhclient.8
+--- dhcp-4.2.2b1/client/dhclient.8.capability  2011-07-01 15:09:06.603784531 +0200
++++ dhcp-4.2.2b1/client/dhclient.8     2011-07-01 15:09:06.663783913 +0200
+@@ -118,6 +118,9 @@ dhclient - Dynamic Host Configuration Pr
+ .B -w
+ ]
+ [
++.B -nc
++]
++[
+ .B -B
+ ]
+ [
+@@ -296,6 +299,32 @@ has been added or removed, so that the c
+ address on that interface.
+ .TP
++.BI \-nc
++Do not drop capabilities.
++
++Normally, if
++.B dhclient
++was compiled with libcap-ng support,
++.B dhclient
++drops most capabilities immediately upon startup.  While more secure,
++this greatly restricts the additional actions that hooks in
++.B dhclient-script (8)
++can take.  (For example, any daemons that 
++.B dhclient-script (8)
++starts or restarts will inherit the restricted capabilities as well,
++which may interfere with their correct operation.)  Thus, the
++.BI \-nc
++option can be used to prevent
++.B dhclient
++from dropping capabilities.
++
++The
++.BI \-nc
++option is ignored if
++.B dhclient
++was not compiled with libcap-ng support.
++
++.TP
+ .BI \-B
+ Set the BOOTP broadcast flag in request packets so servers will always
+ broadcast replies.
+diff -up dhcp-4.2.2b1/client/dhclient.c.capability dhcp-4.2.2b1/client/dhclient.c
+--- dhcp-4.2.2b1/client/dhclient.c.capability  2011-07-01 15:09:06.644784107 +0200
++++ dhcp-4.2.2b1/client/dhclient.c     2011-07-01 15:09:06.664783903 +0200
+@@ -39,6 +39,10 @@
+ #include <limits.h>
+ #include <dns/result.h>
++#ifdef HAVE_LIBCAP_NG
++#include <cap-ng.h>
++#endif
++
+ /*
+  * Defined in stdio.h when _GNU_SOURCE is set, but we don't want to define
+  * that when building ISC code.
+@@ -141,6 +145,9 @@ main(int argc, char **argv) {
+       int timeout_arg = 0;
+       char *arg_conf = NULL;
+       int arg_conf_len = 0;
++#ifdef HAVE_LIBCAP_NG
++      int keep_capabilities = 0;
++#endif
+       /* Initialize client globals. */
+       memset(&default_duid, 0, sizeof(default_duid));
+@@ -410,6 +417,10 @@ main(int argc, char **argv) {
+                       }
+                       dhclient_request_options = argv[i];
++              } else if (!strcmp(argv[i], "-nc")) {
++#ifdef HAVE_LIBCAP_NG
++                      keep_capabilities = 1;
++#endif
+               } else if (argv[i][0] == '-') {
+                   usage();
+               } else if (interfaces_requested < 0) {
+@@ -458,6 +469,19 @@ main(int argc, char **argv) {
+               path_dhclient_script = s;
+       }
++#ifdef HAVE_LIBCAP_NG
++      /* Drop capabilities */
++      if (!keep_capabilities) {
++              capng_clear(CAPNG_SELECT_CAPS);
++              capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
++                              CAP_DAC_OVERRIDE); // Drop this someday
++              capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
++                              CAP_NET_ADMIN, CAP_NET_RAW,
++                              CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN, -1);
++              capng_apply(CAPNG_SELECT_CAPS);
++      }
++#endif
++
+       /* Set up the initial dhcp option universe. */
+       initialize_common_option_spaces();
+diff -up dhcp-4.2.2b1/client/dhclient-script.8.capability dhcp-4.2.2b1/client/dhclient-script.8
+--- dhcp-4.2.2b1/client/dhclient-script.8.capability   2011-07-01 15:09:06.604784521 +0200
++++ dhcp-4.2.2b1/client/dhclient-script.8      2011-07-01 15:09:06.666783883 +0200
+@@ -239,6 +239,16 @@ repeatedly initialized to the values pro
+ the other.   Assuming the information provided by both servers is
+ valid, this shouldn't cause any real problems, but it could be
+ confusing.
++.PP
++Normally, if dhclient was compiled with libcap-ng support,
++dhclient drops most capabilities immediately upon startup.
++While more secure, this greatly restricts the additional actions that
++hooks in dhclient-script can take. For example, any daemons that
++dhclient-script starts or restarts will inherit the restricted
++capabilities as well, which may interfere with their correct operation.
++Thus, the
++.BI \-nc
++option can be used to prevent dhclient from dropping capabilities.
+ .SH SEE ALSO
+ dhclient(8), dhcpd(8), dhcrelay(8), dhclient.conf(5) and
+ dhclient.leases(5).
+diff -up dhcp-4.2.2b1/client/Makefile.am.capability dhcp-4.2.2b1/client/Makefile.am
+--- dhcp-4.2.2b1/client/Makefile.am.capability 2011-07-01 15:09:06.526785327 +0200
++++ dhcp-4.2.2b1/client/Makefile.am    2011-07-01 15:09:06.667783873 +0200
+@@ -5,7 +5,7 @@ dhclient_SOURCES = clparse.c dhclient.c 
+                  scripts/netbsd scripts/nextstep scripts/openbsd \
+                  scripts/solaris scripts/openwrt
+ dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+-               $(BIND9_LIBDIR) -ldns-export -lisc-export
++               $(BIND9_LIBDIR) -ldns-export -lisc-export $(CAPNG_LDADD)
+ man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
+ EXTRA_DIST = $(man_MANS)
+diff -up dhcp-4.2.2b1/configure.ac.capability dhcp-4.2.2b1/configure.ac
+--- dhcp-4.2.2b1/configure.ac.capability       2011-07-01 15:09:06.527785317 +0200
++++ dhcp-4.2.2b1/configure.ac  2011-07-01 15:09:06.667783873 +0200
+@@ -449,6 +449,41 @@ AC_TRY_LINK(
+ # Look for optional headers.
+ AC_CHECK_HEADERS(sys/socket.h net/if_dl.h net/if6.h regex.h)
++# look for capabilities library
++AC_ARG_WITH(libcap-ng,
++    [  --with-libcap-ng=[auto/yes/no]  Add Libcap-ng support [default=auto]],,
++    with_libcap_ng=auto)
++
++# Check for Libcap-ng API
++#
++# libcap-ng detection
++if test x$with_libcap_ng = xno ; then
++    have_libcap_ng=no;
++else
++    # Start by checking for header file
++    AC_CHECK_HEADER(cap-ng.h, capng_headers=yes, capng_headers=no)
++
++    # See if we have libcap-ng library
++    AC_CHECK_LIB(cap-ng, capng_clear,
++                 CAPNG_LDADD=-lcap-ng,)
++
++    # Check results are usable
++    if test x$with_libcap_ng = xyes -a x$CAPNG_LDADD = x ; then
++       AC_MSG_ERROR(libcap-ng support was requested and the library was not found)
++    fi
++    if test x$CAPNG_LDADD != x -a $capng_headers = no ; then
++       AC_MSG_ERROR(libcap-ng libraries found but headers are missing)
++    fi
++fi
++AC_SUBST(CAPNG_LDADD)
++AC_MSG_CHECKING(whether to use libcap-ng)
++if test x$CAPNG_LDADD != x ; then
++    AC_DEFINE(HAVE_LIBCAP_NG,1,[libcap-ng support])
++    AC_MSG_RESULT(yes)
++else
++    AC_MSG_RESULT(no)
++fi
++
+ # Solaris needs some libraries for functions
+ AC_SEARCH_LIBS(socket, [socket])
+ AC_SEARCH_LIBS(inet_ntoa, [nsl])
+diff -up dhcp-4.2.2b1/relay/dhcrelay.c.capability dhcp-4.2.2b1/relay/dhcrelay.c
+--- dhcp-4.2.2b1/relay/dhcrelay.c.capability   2011-07-01 15:09:06.626784295 +0200
++++ dhcp-4.2.2b1/relay/dhcrelay.c      2011-07-01 15:12:05.362223794 +0200
+@@ -36,6 +36,11 @@
+ #include <syslog.h>
+ #include <sys/time.h>
++#ifdef HAVE_LIBCAP_NG
++#  include <cap-ng.h>
++   int keep_capabilities = 0;
++#endif
++
+ TIME default_lease_time = 43200; /* 12 hours... */
+ TIME max_lease_time = 86400; /* 24 hours... */
+ struct tree_cache *global_options[256];
+@@ -356,6 +361,10 @@ main(int argc, char **argv) {
+                       sl->next = upstreams;
+                       upstreams = sl;
+ #endif
++              } else if (!strcmp(argv[i], "-nc")) {
++#ifdef HAVE_LIBCAP_NG
++                      keep_capabilities = 1;
++#endif
+               } else if (!strcmp(argv[i], "-pf")) {
+                       if (++i == argc)
+                               usage();
+@@ -426,6 +435,17 @@ main(int argc, char **argv) {
+ #endif
+       }
++#ifdef HAVE_LIBCAP_NG
++      /* Drop capabilities */
++      if (!keep_capabilities) {
++              capng_clear(CAPNG_SELECT_BOTH);
++              capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
++                              CAP_NET_RAW, CAP_NET_BIND_SERVICE, -1);
++              capng_apply(CAPNG_SELECT_BOTH);
++              log_info ("Dropped all unnecessary capabilities.");
++      }
++#endif
++
+       if (!quiet) {
+               log_info("%s %s", message, PACKAGE_VERSION);
+               log_info(copyright);
+@@ -573,6 +593,15 @@ main(int argc, char **argv) {
+               dhcpv6_packet_handler = do_packet6;
+ #endif
++#ifdef HAVE_LIBCAP_NG
++      /* Drop all capabilities */
++      if (!keep_capabilities) {
++              capng_clear(CAPNG_SELECT_BOTH);
++              capng_apply(CAPNG_SELECT_BOTH);
++              log_info ("Dropped all capabilities.");
++      }
++#endif
++
+       /* Start dispatching packets and timeouts... */
+       dispatch();
+diff -up dhcp-4.2.2b1/relay/Makefile.am.capability dhcp-4.2.2b1/relay/Makefile.am
+--- dhcp-4.2.2b1/relay/Makefile.am.capability  2011-07-01 15:09:06.546785121 +0200
++++ dhcp-4.2.2b1/relay/Makefile.am     2011-07-01 15:09:06.670783841 +0200
+@@ -3,7 +3,7 @@ AM_CPPFLAGS = -DLOCALSTATEDIR='"@localst
+ sbin_PROGRAMS = dhcrelay
+ dhcrelay_SOURCES = dhcrelay.c
+ dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+-               $(BIND9_LIBDIR) -ldns-export -lisc-export
++               $(BIND9_LIBDIR) -ldns-export -lisc-export $(CAPNG_LDADD)
+ man_MANS = dhcrelay.8
+ EXTRA_DIST = $(man_MANS)
+diff -up dhcp-4.2.2b1/server/dhcpd.c.capability dhcp-4.2.2b1/server/dhcpd.c
+--- dhcp-4.2.2b1/server/dhcpd.c.capability     2011-07-01 15:09:06.636784192 +0200
++++ dhcp-4.2.2b1/server/dhcpd.c        2011-07-01 15:09:06.670783841 +0200
+@@ -58,6 +58,11 @@ static const char url [] =
+ #  undef group
+ #endif /* PARANOIA */
++#ifdef HAVE_LIBCAP_NG
++#  include <cap-ng.h>
++   int keep_capabilities = 0;
++#endif
++
+ static void usage(void);
+ struct iaddr server_identifier;
+@@ -403,6 +408,10 @@ main(int argc, char **argv) {
+                       traceinfile = argv [i];
+                       trace_replay_init ();
+ #endif /* TRACING */
++              } else if (!strcmp(argv[i], "-nc")) {
++#ifdef HAVE_LIBCAP_NG
++                      keep_capabilities = 1;
++#endif
+               } else if (argv [i][0] == '-') {
+                       usage ();
+               } else {
+@@ -459,6 +468,17 @@ main(int argc, char **argv) {
+         }
+ #endif /* DHCPv6 */
++#ifdef HAVE_LIBCAP_NG
++      /* Drop capabilities */
++      if (!keep_capabilities) {
++              capng_clear(CAPNG_SELECT_BOTH);
++              capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
++                              CAP_NET_RAW, CAP_NET_BIND_SERVICE, CAP_SYS_CHROOT, CAP_SETUID, CAP_SETGID, -1);
++              capng_apply(CAPNG_SELECT_BOTH);
++              log_info ("Dropped all unnecessary capabilities.");
++      }
++#endif
++
+         /*
+          * convert relative path names to absolute, for files that need
+          * to be reopened after chdir() has been called
+@@ -859,6 +879,15 @@ main(int argc, char **argv) {
+       omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
+                            (omapi_object_t *)0, "state", server_running);
++#ifdef HAVE_LIBCAP_NG
++      /* Drop all capabilities */
++      if (!keep_capabilities) {
++              capng_clear(CAPNG_SELECT_BOTH);
++              capng_apply(CAPNG_SELECT_BOTH);
++              log_info ("Dropped all capabilities.");
++      }
++#endif
++
+       /* Receive packets and dispatch them... */
+       dispatch ();
+diff -up dhcp-4.2.2b1/server/Makefile.am.capability dhcp-4.2.2b1/server/Makefile.am
+--- dhcp-4.2.2b1/server/Makefile.am.capability 2011-07-01 15:09:06.546785121 +0200
++++ dhcp-4.2.2b1/server/Makefile.am    2011-07-01 15:09:06.671783830 +0200
+@@ -8,7 +8,8 @@ dhcpd_SOURCES = dhcpd.c dhcp.c bootp.c c
+ dhcpd_CFLAGS = $(LDAP_CFLAGS)
+ dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+-            ../dhcpctl/libdhcpctl.a $(BIND9_LIBDIR) -ldns-export -lisc-export
++            ../dhcpctl/libdhcpctl.a $(BIND9_LIBDIR) -ldns-export -lisc-export \
++            $(CAPNG_LDADD)
+ man_MANS = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
+ EXTRA_DIST = $(man_MANS)
diff --git a/src/patches/dhcp-4.2.2-dhclient-usage.patch b/src/patches/dhcp-4.2.2-dhclient-usage.patch
new file mode 100644 (file)
index 0000000..0d41943
--- /dev/null
@@ -0,0 +1,14 @@
+diff -up dhcp-4.2.2b1/client/dhclient.c.usage dhcp-4.2.2b1/client/dhclient.c
+--- dhcp-4.2.2b1/client/dhclient.c.usage       2011-07-01 13:55:16.000000000 +0200
++++ dhcp-4.2.2b1/client/dhclient.c     2011-07-01 13:58:55.243800602 +0200
+@@ -1047,6 +1047,10 @@ static void usage()
+                 "                [-s server-addr] [-cf config-file] "
+                 "[-lf lease-file]\n"
+                 "                [-pf pid-file] [--no-pid] [-e VAR=val]\n"
++                "                [-I <dhcp-client-identifier>] [-B]\n"
++                "                [-H <host-name> | -F <fqdn.fqdn>] [-timeout <timeout>]\n"
++                "                [-V <vendor-class-identifier>]\n"
++                "                [-R <request option list>]\n"
+                 "                [-sf script-file] [interface]");
+ }
diff --git a/src/patches/dhcp-4.2.2-gpxe-cid.patch b/src/patches/dhcp-4.2.2-gpxe-cid.patch
new file mode 100644 (file)
index 0000000..c0be4c2
--- /dev/null
@@ -0,0 +1,132 @@
+diff -up dhcp-4.2.2/client/dhclient.c.gpxe-cid dhcp-4.2.2/client/dhclient.c
+--- dhcp-4.2.2/client/dhclient.c.gpxe-cid      2011-09-16 18:23:20.190453902 +0200
++++ dhcp-4.2.2/client/dhclient.c       2011-09-16 18:27:15.568463599 +0200
+@@ -58,6 +58,13 @@ const char *path_dhclient_pid = NULL;
+ static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT;
+ char *path_dhclient_script = path_dhclient_script_array;
++/* Default Prefix */
++static unsigned char default_prefix[12] = {
++      0xff, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x02, 0x00,
++      0x00, 0x02, 0xc9, 0x00
++};
++
+ /* False (default) => we write and use a pid file */
+ isc_boolean_t no_pid_file = ISC_FALSE;
+@@ -1250,6 +1257,12 @@ int find_subnet (struct subnet **sp,
+ static void setup_ib_interface(struct interface_info *ip)
+ {
+       struct group *g;
++      struct hardware *hw = &ip->hw_address;
++      char client_id[64];
++      char *arg_conf = NULL;
++      int arg_conf_len = 0;
++      isc_result_t status;
++      struct parse *cfile = (struct parse *)0;
+       /* Set the broadcast flag */
+       ip->client->config->bootp_broadcast_always = 1;
+@@ -1266,8 +1279,39 @@ static void setup_ib_interface(struct in
+               }
+       }
+-      /* No client ID specified */
+-      log_fatal("dhcp-client-identifier must be specified for InfiniBand");
++      /*
++       * No client ID specified, make up one based on a default
++       * "prefix" and the port GUID.
++       *
++       * NOTE: This is compatible with what gpxe does.
++       */
++      sprintf(client_id, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
++              default_prefix[0], default_prefix[1], default_prefix[2],
++              default_prefix[3], default_prefix[4], default_prefix[5],
++              default_prefix[6], default_prefix[7], default_prefix[8],
++              default_prefix[9], default_prefix[10], default_prefix[11],
++              hw->hbuf[1], hw->hbuf[2], hw->hbuf[3], hw->hbuf[4],
++              hw->hbuf[5], hw->hbuf[6], hw->hbuf[7], hw->hbuf[8]);
++
++      arg_conf_len = asprintf(&arg_conf,
++                              "send dhcp-client-identifier %s;",
++                              client_id);
++
++      if ((arg_conf == 0) || (arg_conf_len <= 0))
++              log_fatal("Unable to send option dhcp-client-identifier");
++
++      status = new_parse(&cfile, -1, arg_conf, arg_conf_len,
++                         "Automatic Infiniband client identifier", 0);
++
++      if ((status != ISC_R_SUCCESS) || (cfile->warnings_occurred))
++              log_fatal("Failed to parse Infiniband client identifier");
++
++      parse_client_statement(cfile, NULL, ip->client->config);
++
++      if (cfile->warnings_occurred)
++              log_fatal("Failed to parse Infiniband client identifier");
++
++      end_parse(&cfile);
+ }
+ /* Individual States:
+diff -up dhcp-4.2.2/common/lpf.c.gpxe-cid dhcp-4.2.2/common/lpf.c
+--- dhcp-4.2.2/common/lpf.c.gpxe-cid   2011-09-16 18:23:20.183453996 +0200
++++ dhcp-4.2.2/common/lpf.c    2011-09-16 18:25:28.235804421 +0200
+@@ -591,6 +591,37 @@ void maybe_setup_fallback ()
+       }
+ }
++static unsigned char * get_ib_hw_addr(char * name)
++{
++      struct ifaddrs *ifaddrs;
++      struct ifaddrs *ifa;
++      struct sockaddr_ll *sll = NULL;
++      static unsigned char hw_addr[8];
++
++      if (getifaddrs(&ifaddrs) == -1)
++              return NULL;
++
++      for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
++              if (ifa->ifa_addr == NULL)
++                      continue;
++              if (ifa->ifa_addr->sa_family != AF_PACKET)
++                      continue;
++              if (ifa->ifa_flags & IFF_LOOPBACK)
++                      continue;
++              if (strcmp(ifa->ifa_name, name) == 0) {
++                      sll = (struct sockaddr_ll *)(void *)ifa->ifa_addr;
++                      break;
++              }
++      }
++      if (sll == NULL) {
++              freeifaddrs(ifaddrs);
++              return NULL;
++      }
++      memcpy(hw_addr, &sll->sll_addr[sll->sll_halen - 8], 8);
++      freeifaddrs(ifaddrs);
++      return (unsigned char *)&hw_addr;
++}
++
+ void
+ get_hw_addr(struct interface_info *info)
+ {
+@@ -599,6 +630,7 @@ get_hw_addr(struct interface_info *info)
+       struct ifaddrs *ifaddrs;
+       struct ifaddrs *ifa;
+       struct sockaddr_ll *sll = NULL;
++      unsigned char *hw_addr;
+       if (getifaddrs(&ifaddrs) == -1)
+               log_fatal("Failed to get interfaces");
+@@ -660,6 +692,10 @@ get_hw_addr(struct interface_info *info)
+                       hw->hlen = 1;
+                       hw->hbuf[0] = HTYPE_INFINIBAND;
++                      hw_addr = get_ib_hw_addr(name);
++                      if (!hw_addr)
++                              log_fatal("Failed getting %s hw addr", name);
++                      memcpy (&hw->hbuf [1], hw_addr, 8);
+                       break;
+ #if defined(ARPHRD_PPP)
+               case ARPHRD_PPP:
diff --git a/src/patches/dhcp-4.2.2-improved-xid.patch b/src/patches/dhcp-4.2.2-improved-xid.patch
new file mode 100644 (file)
index 0000000..f49fc78
--- /dev/null
@@ -0,0 +1,138 @@
+diff -up dhcp-4.2.2/client/dhclient.c.improved-xid dhcp-4.2.2/client/dhclient.c
+--- dhcp-4.2.2/client/dhclient.c.improved-xid  2011-09-16 18:18:00.649730661 +0200
++++ dhcp-4.2.2/client/dhclient.c       2011-09-16 18:22:36.815035513 +0200
+@@ -898,6 +898,26 @@ main(int argc, char **argv) {
+               }
+       }
++      /* We create a backup seed before rediscovering interfaces in order to
++         have a seed built using all of the available interfaces
++         It's interesting if required interfaces doesn't let us defined
++         a really unique seed due to a lack of valid HW addr later
++         (this is the case with DHCP over IB)
++         We only use the last device as using a sum could broke the
++         uniqueness of the seed among multiple nodes
++       */
++      unsigned backup_seed = 0;
++      for (ip = interfaces; ip; ip = ip -> next) {
++              int junk;
++              if ( ip -> hw_address.hlen <= sizeof seed )
++                continue;
++              memcpy (&junk,
++                      &ip -> hw_address.hbuf [ip -> hw_address.hlen -
++                                              sizeof seed], sizeof seed);
++              backup_seed = junk;
++      }
++
++
+       /* At this point, all the interfaces that the script thinks
+          are relevant should be running, so now we once again call
+          discover_interfaces(), and this time ask it to actually set
+@@ -912,14 +932,36 @@ main(int argc, char **argv) {
+          Not much entropy, but we're booting, so we're not likely to
+          find anything better. */
+       seed = 0;
++      int seed_flag = 0;
+       for (ip = interfaces; ip; ip = ip->next) {
+               int junk;
++              if ( ip -> hw_address.hlen <= sizeof seed )
++                continue;
+               memcpy(&junk,
+                      &ip->hw_address.hbuf[ip->hw_address.hlen -
+                                           sizeof seed], sizeof seed);
+               seed += junk;
++              seed_flag = 1;
+       }
+-      srandom(seed + cur_time + (unsigned)getpid());
++      if ( seed_flag == 0 ) {
++              if ( backup_seed != 0 ) {
++                seed = backup_seed;
++                log_info ("xid: rand init seed (0x%x) built using all"
++                          " available interfaces",seed);
++              }
++              else {
++                seed = cur_time^((unsigned) gethostid()) ;
++                log_info ("xid: warning: no netdev with useable HWADDR found"
++                          " for seed's uniqueness enforcement");
++                log_info ("xid: rand init seed (0x%x) built using gethostid",
++                          seed);
++              }
++              /* we only use seed and no current time as a broadcast reply */
++              /* will certainly be used by the hwaddrless interface */
++              srandom(seed);
++      }
++      else
++              srandom(seed + cur_time + (unsigned)getpid());
+       /* Setup specific Infiniband options */
+       for (ip = interfaces; ip; ip = ip->next) {
+@@ -1457,7 +1499,7 @@ void dhcpack (packet)
+               return;
+       }
+-      log_info ("DHCPACK from %s", piaddr (packet -> client_addr));
++      log_info ("DHCPACK from %s (xid=0x%x)", piaddr (packet -> client_addr), client -> xid);
+       lease = packet_to_lease (packet, client);
+       if (!lease) {
+@@ -2174,7 +2216,7 @@ void dhcpnak (packet)
+               return;
+       }
+-      log_info ("DHCPNAK from %s", piaddr (packet -> client_addr));
++      log_info ("DHCPNAK from %s (xid=0x%x)", piaddr (packet -> client_addr), client -> xid);
+       if (!client -> active) {
+ #if defined (DEBUG)
+@@ -2300,10 +2342,10 @@ void send_discover (cpp)
+               client -> packet.secs = htons (65535);
+       client -> secs = client -> packet.secs;
+-      log_info ("DHCPDISCOVER on %s to %s port %d interval %ld",
++      log_info ("DHCPDISCOVER on %s to %s port %d interval %ld (xid=0x%x)",
+             client -> name ? client -> name : client -> interface -> name,
+             inet_ntoa (sockaddr_broadcast.sin_addr),
+-            ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval));
++            ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval), client -> xid);
+       /* Send out a packet. */
+       result = send_packet (client -> interface, (struct packet *)0,
+@@ -2584,10 +2626,10 @@ void send_request (cpp)
+                       client -> packet.secs = htons (65535);
+       }
+-      log_info ("DHCPREQUEST on %s to %s port %d",
++      log_info ("DHCPREQUEST on %s to %s port %d (xid=0x%x)",
+             client -> name ? client -> name : client -> interface -> name,
+             inet_ntoa (destination.sin_addr),
+-            ntohs (destination.sin_port));
++            ntohs (destination.sin_port), client -> xid);
+       if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
+           fallback_interface)
+@@ -2618,10 +2660,10 @@ void send_decline (cpp)
+       int result;
+-      log_info ("DHCPDECLINE on %s to %s port %d",
++      log_info ("DHCPDECLINE on %s to %s port %d (xid=0x%x)",
+             client -> name ? client -> name : client -> interface -> name,
+             inet_ntoa (sockaddr_broadcast.sin_addr),
+-            ntohs (sockaddr_broadcast.sin_port));
++            ntohs (sockaddr_broadcast.sin_port), client -> xid);
+       /* Send out a packet. */
+       result = send_packet (client -> interface, (struct packet *)0,
+@@ -2661,10 +2703,10 @@ void send_release (cpp)
+               return;
+       }
+-      log_info ("DHCPRELEASE on %s to %s port %d",
++      log_info ("DHCPRELEASE on %s to %s port %d (xid=0x%x)",
+             client -> name ? client -> name : client -> interface -> name,
+             inet_ntoa (destination.sin_addr),
+-            ntohs (destination.sin_port));
++            ntohs (destination.sin_port), client -> xid);
+       if (fallback_interface)
+               result = send_packet (fallback_interface,
diff --git a/src/patches/dhcp-4.2.2-lpf-ib.patch b/src/patches/dhcp-4.2.2-lpf-ib.patch
new file mode 100644 (file)
index 0000000..4034028
--- /dev/null
@@ -0,0 +1,538 @@
+diff -up dhcp-4.2.2/client/dhclient.c.lpf-ib dhcp-4.2.2/client/dhclient.c
+--- dhcp-4.2.2/client/dhclient.c.lpf-ib        2011-09-19 11:24:08.693775799 +0200
++++ dhcp-4.2.2/client/dhclient.c       2011-09-19 11:24:08.703775541 +0200
+@@ -113,6 +113,8 @@ static int check_domain_name_list(const 
+ static int check_option_values(struct universe *universe, unsigned int opt,
+                              const char *ptr, size_t len);
++static void setup_ib_interface(struct interface_info *ip);
++
+ int
+ main(int argc, char **argv) {
+       int fd;
+@@ -919,6 +921,14 @@ main(int argc, char **argv) {
+       }
+       srandom(seed + cur_time + (unsigned)getpid());
++      /* Setup specific Infiniband options */
++      for (ip = interfaces; ip; ip = ip->next) {
++              if (ip->client &&
++                  (ip->hw_address.hbuf[0] == HTYPE_INFINIBAND)) {
++                      setup_ib_interface(ip);
++              }
++      }
++
+       /* Start a configuration state machine for each interface. */
+ #ifdef DHCPv6
+       if (local_family == AF_INET6) {
+@@ -1195,6 +1205,29 @@ int find_subnet (struct subnet **sp,
+       return 0;
+ }
++static void setup_ib_interface(struct interface_info *ip)
++{
++      struct group *g;
++
++      /* Set the broadcast flag */
++      ip->client->config->bootp_broadcast_always = 1;
++
++      /*
++       * Find out if a dhcp-client-identifier option was specified either
++       * in the config file or on the command line
++       */
++      for (g = ip->client->config->on_transmission; g != NULL; g = g->next) {
++              if ((g->statements != NULL) &&
++                  (strcmp(g->statements->data.option->option->name,
++                          "dhcp-client-identifier") == 0)) {
++                      return;
++              }
++      }
++
++      /* No client ID specified */
++      log_fatal("dhcp-client-identifier must be specified for InfiniBand");
++}
++
+ /* Individual States:
+  *
+  * Each routine is called from the dhclient_state_machine() in one of
+diff -up dhcp-4.2.2/common/bpf.c.lpf-ib dhcp-4.2.2/common/bpf.c
+--- dhcp-4.2.2/common/bpf.c.lpf-ib     2011-09-19 11:24:08.694775773 +0200
++++ dhcp-4.2.2/common/bpf.c    2011-09-19 11:24:08.704775516 +0200
+@@ -198,11 +198,44 @@ struct bpf_insn dhcp_bpf_filter [] = {
+       BPF_STMT(BPF_RET+BPF_K, 0),
+ };
++/* Packet filter program for DHCP over Infiniband.
++ *
++ * XXX
++ * Changes to the filter program may require changes to the constant offsets
++ * used in lpf_gen_filter_setup to patch the port in the BPF program!
++ * XXX
++ */
++struct bpf_insn dhcp_ib_bpf_filter [] = {
++      /* Packet filter for Infiniband */
++      /* Make sure it's a UDP packet... */
++      BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 9),
++      BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
++
++      /* Make sure this isn't a fragment... */
++      BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 6),
++      BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
++
++      /* Get the IP header length... */
++      BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0),
++
++      /* Make sure it's to the right port... */
++      BPF_STMT(BPF_LD + BPF_H + BPF_IND, 2),
++      BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
++
++      /* If we passed all the tests, ask for the whole packet. */
++      BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
++
++      /* Otherwise, drop it. */
++      BPF_STMT(BPF_RET + BPF_K, 0),
++};
++
+ #if defined (DEC_FDDI)
+ struct bpf_insn *bpf_fddi_filter;
+ #endif
+ int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn);
++int dhcp_ib_bpf_filter_len = sizeof dhcp_ib_bpf_filter / sizeof (struct bpf_insn);
++
+ #if defined (HAVE_TR_SUPPORT)
+ struct bpf_insn dhcp_bpf_tr_filter [] = {
+         /* accept all token ring packets due to variable length header */
+diff -up dhcp-4.2.2/common/lpf.c.lpf-ib dhcp-4.2.2/common/lpf.c
+--- dhcp-4.2.2/common/lpf.c.lpf-ib     2011-09-19 11:24:08.694775773 +0200
++++ dhcp-4.2.2/common/lpf.c    2011-09-19 11:26:15.107109935 +0200
+@@ -42,6 +42,7 @@
+ #include "includes/netinet/udp.h"
+ #include "includes/netinet/if_ether.h"
+ #include <net/if.h>
++#include <ifaddrs.h>
+ #ifndef PACKET_AUXDATA
+ #define PACKET_AUXDATA 8
+@@ -59,6 +60,15 @@ struct tpacket_auxdata
+ /* Reinitializes the specified interface after an address change.   This
+    is not required for packet-filter APIs. */
++/* Default broadcast address for IPoIB */
++static unsigned char default_ib_bcast_addr[20] = {
++      0x00, 0xff, 0xff, 0xff,
++      0xff, 0x12, 0x40, 0x1b,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00,
++      0xff, 0xff, 0xff, 0xff
++};
++
+ #ifdef USE_LPF_SEND
+ void if_reinitialize_send (info)
+       struct interface_info *info;
+@@ -86,10 +96,21 @@ int if_register_lpf (info)
+               struct sockaddr common;
+       } sa;
+       struct ifreq ifr;
++      int type;
++      int protocol;
+       /* Make an LPF socket. */
+-      if ((sock = socket(PF_PACKET, SOCK_RAW,
+-                         htons((short)ETH_P_ALL))) < 0) {
++      get_hw_addr(info);
++
++      if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++              type = SOCK_DGRAM;
++              protocol = ETHERTYPE_IP;
++      } else {
++              type = SOCK_RAW;
++              protocol = ETH_P_ALL;
++      }
++
++      if ((sock = socket(PF_PACKET, type, htons((short)protocol))) < 0) {
+               if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+                   errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+                   errno == EAFNOSUPPORT || errno == EINVAL) {
+@@ -112,6 +133,7 @@ int if_register_lpf (info)
+       /* Bind to the interface name */
+       memset (&sa, 0, sizeof sa);
+       sa.ll.sll_family = AF_PACKET;
++      sa.ll.sll_protocol = htons(protocol);
+       sa.ll.sll_ifindex = ifr.ifr_ifindex;
+       if (bind (sock, &sa.common, sizeof sa)) {
+               if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+@@ -127,8 +149,6 @@ int if_register_lpf (info)
+               log_fatal ("Bind socket to interface: %m");
+       }
+-      get_hw_addr(info->name, &info->hw_address);
+-
+       return sock;
+ }
+ #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
+@@ -183,6 +203,8 @@ void if_deregister_send (info)
+    in bpf includes... */
+ extern struct sock_filter dhcp_bpf_filter [];
+ extern int dhcp_bpf_filter_len;
++extern struct sock_filter dhcp_ib_bpf_filter [];
++extern int dhcp_ib_bpf_filter_len;
+ #if defined (HAVE_TR_SUPPORT)
+ extern struct sock_filter dhcp_bpf_tr_filter [];
+@@ -200,11 +222,13 @@ void if_register_receive (info)
+       /* Open a LPF device and hang it on this interface... */
+       info -> rfdesc = if_register_lpf (info);
+-      val = 1;
+-      if (setsockopt (info -> rfdesc, SOL_PACKET, PACKET_AUXDATA, &val,
+-                      sizeof val) < 0) {
+-              if (errno != ENOPROTOOPT)
+-                      log_fatal ("Failed to set auxiliary packet data: %m");
++      if (info->hw_address.hbuf[0] != HTYPE_INFINIBAND) {
++              val = 1;
++              if (setsockopt (info -> rfdesc, SOL_PACKET, PACKET_AUXDATA,
++                              &val, sizeof val) < 0) {
++                      if (errno != ENOPROTOOPT)
++                              log_fatal ("Failed to set auxiliary packet data: %m");
++              }
+       }
+ #if defined (HAVE_TR_SUPPORT)
+@@ -250,15 +274,28 @@ static void lpf_gen_filter_setup (info)
+       memset(&p, 0, sizeof(p));
+-      /* Set up the bpf filter program structure.    This is defined in
+-         bpf.c */
+-      p.len = dhcp_bpf_filter_len;
+-      p.filter = dhcp_bpf_filter;
+-
+-        /* Patch the server port into the LPF  program...
+-         XXX changes to filter program may require changes
+-         to the insn number(s) used below! XXX */
+-      dhcp_bpf_filter [8].k = ntohs ((short)local_port);
++      if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++              /* Set up the bpf filter program structure. */
++              p.len = dhcp_ib_bpf_filter_len;
++              p.filter = dhcp_ib_bpf_filter;
++
++              /* Patch the server port into the LPF program...
++                 XXX
++                 changes to filter program may require changes
++                 to the insn number(s) used below!
++                 XXX */
++              dhcp_ib_bpf_filter[6].k = ntohs ((short)local_port);
++      } else {
++              /* Set up the bpf filter program structure.
++                 This is defined in bpf.c */
++              p.len = dhcp_bpf_filter_len;
++              p.filter = dhcp_bpf_filter;
++
++              /* Patch the server port into the LPF  program...
++                 XXX changes to filter program may require changes
++                 to the insn number(s) used below! XXX */
++              dhcp_bpf_filter [8].k = ntohs ((short)local_port);
++      }
+       if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
+                       sizeof p) < 0) {
+@@ -315,6 +352,54 @@ static void lpf_tr_filter_setup (info)
+ #endif /* USE_LPF_RECEIVE */
+ #ifdef USE_LPF_SEND
++ssize_t send_packet_ib(interface, packet, raw, len, from, to, hto)
++      struct interface_info *interface;
++      struct packet *packet;
++      struct dhcp_packet *raw;
++      size_t len;
++      struct in_addr from;
++      struct sockaddr_in *to;
++      struct hardware *hto;
++{
++      unsigned ibufp = 0;
++      double ih [1536 / sizeof (double)];
++      unsigned char *buf = (unsigned char *)ih;
++      ssize_t result;
++
++      union sockunion {
++              struct sockaddr sa;
++              struct sockaddr_ll sll;
++              struct sockaddr_storage ss;
++      } su;
++
++      assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr,
++                              to->sin_addr.s_addr, to->sin_port,
++                              (unsigned char *)raw, len);
++      memcpy (buf + ibufp, raw, len);
++
++      memset(&su, 0, sizeof(su));
++      su.sll.sll_family = AF_PACKET;
++      su.sll.sll_protocol = htons(ETHERTYPE_IP);
++
++      if (!(su.sll.sll_ifindex = if_nametoindex(interface->name))) {
++              errno = ENOENT;
++              log_error ("send_packet_ib: %m - failed to get if index");
++              return -1;
++      }
++
++      su.sll.sll_hatype = htons(HTYPE_INFINIBAND);
++      su.sll.sll_halen = sizeof(interface->bcast_addr);
++      memcpy(&su.sll.sll_addr, interface->bcast_addr, 20);
++
++      result = sendto(interface->wfdesc, buf, ibufp + len, 0,
++                      &su.sa, sizeof(su));
++
++      if (result < 0)
++              log_error ("send_packet_ib: %m");
++
++      return result;
++}
++
+ ssize_t send_packet (interface, packet, raw, len, from, to, hto)
+       struct interface_info *interface;
+       struct packet *packet;
+@@ -335,6 +420,11 @@ ssize_t send_packet (interface, packet, 
+               return send_fallback (interface, packet, raw,
+                                     len, from, to, hto);
++      if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++              return send_packet_ib(interface, packet, raw, len, from,
++                                    to, hto);
++      }
++
+       if (hto == NULL && interface->anycast_mac_addr.hlen)
+               hto = &interface->anycast_mac_addr;
+@@ -356,6 +446,42 @@ ssize_t send_packet (interface, packet, 
+ #endif /* USE_LPF_SEND */
+ #ifdef USE_LPF_RECEIVE
++ssize_t receive_packet_ib (interface, buf, len, from, hfrom)
++      struct interface_info *interface;
++      unsigned char *buf;
++      size_t len;
++      struct sockaddr_in *from;
++      struct hardware *hfrom;
++{
++      int length = 0;
++      int offset = 0;
++      unsigned char ibuf [1536];
++      unsigned bufix = 0;
++      unsigned paylen;
++
++      length = read(interface->rfdesc, ibuf, sizeof(ibuf));
++
++      if (length <= 0)
++              return length;
++
++      offset = decode_udp_ip_header(interface, ibuf, bufix, from,
++                                     (unsigned)length, &paylen, 0);
++
++      if (offset < 0)
++              return 0;
++
++      bufix += offset;
++      length -= offset;
++
++      if (length < paylen)
++              log_fatal("Internal inconsistency at %s:%d.", MDL);
++
++      /* Copy out the data in the packet... */
++      memcpy(buf, &ibuf[bufix], paylen);
++
++      return (ssize_t)paylen;
++}
++
+ ssize_t receive_packet (interface, buf, len, from, hfrom)
+       struct interface_info *interface;
+       unsigned char *buf;
+@@ -382,6 +508,10 @@ ssize_t receive_packet (interface, buf, 
+       };
+       struct cmsghdr *cmsg;
++      if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++              return receive_packet_ib(interface, buf, len, from, hfrom);
++      }
++
+       length = recvmsg (interface -> rfdesc, &msg, 0);
+       if (length <= 0)
+               return length;
+@@ -462,33 +592,44 @@ void maybe_setup_fallback ()
+ }
+ void
+-get_hw_addr(const char *name, struct hardware *hw) {
+-      int sock;
+-      struct ifreq tmp;
+-      struct sockaddr *sa;
++get_hw_addr(struct interface_info *info)
++{
++      struct hardware *hw = &info->hw_address;
++      char *name = info->name;
++      struct ifaddrs *ifaddrs;
++      struct ifaddrs *ifa;
++      struct sockaddr_ll *sll = NULL;
+-      if (strlen(name) >= sizeof(tmp.ifr_name)) {
+-              log_fatal("Device name too long: \"%s\"", name);
+-      }
++      if (getifaddrs(&ifaddrs) == -1)
++              log_fatal("Failed to get interfaces");
+-      sock = socket(AF_INET, SOCK_DGRAM, 0);
+-      if (sock < 0) {
+-              log_fatal("Can't create socket for \"%s\": %m", name);
++      for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
++
++              if (ifa->ifa_addr == NULL)
++                      continue;
++
++              if (ifa->ifa_addr->sa_family != AF_PACKET)
++                      continue;
++
++              if (ifa->ifa_flags & IFF_LOOPBACK)
++                      continue;
++
++              if (strcmp(ifa->ifa_name, name) == 0) {
++                      sll = (struct sockaddr_ll *)(void *)ifa->ifa_addr;
++                      break;
++              }
+       }
+-      memset(&tmp, 0, sizeof(tmp));
+-      strcpy(tmp.ifr_name, name);
+-      if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
+-              log_fatal("Error getting hardware address for \"%s\": %m", 
+-                        name);
++      if (sll == NULL) {
++              freeifaddrs(ifaddrs);
++              log_fatal("Failed to get HW address for %s\n", name);
+       }
+-      sa = &tmp.ifr_hwaddr;
+-      switch (sa->sa_family) {
++      switch (sll->sll_hatype) {
+               case ARPHRD_ETHER:
+                       hw->hlen = 7;
+                       hw->hbuf[0] = HTYPE_ETHER;
+-                      memcpy(&hw->hbuf[1], sa->sa_data, 6);
++                      memcpy(&hw->hbuf[1], sll->sll_addr, 6);
+                       break;
+               case ARPHRD_IEEE802:
+ #ifdef ARPHRD_IEEE802_TR
+@@ -496,18 +637,35 @@ get_hw_addr(const char *name, struct har
+ #endif /* ARPHRD_IEEE802_TR */
+                       hw->hlen = 7;
+                       hw->hbuf[0] = HTYPE_IEEE802;
+-                      memcpy(&hw->hbuf[1], sa->sa_data, 6);
++                      memcpy(&hw->hbuf[1], sll->sll_addr, 6);
+                       break;
+               case ARPHRD_FDDI:
+                       hw->hlen = 17;
+                       hw->hbuf[0] = HTYPE_FDDI;
+-                      memcpy(&hw->hbuf[1], sa->sa_data, 16);
++                      memcpy(&hw->hbuf[1], sll->sll_addr, 16);
++                      break;
++              case ARPHRD_INFINIBAND:
++                      /* For Infiniband, save the broadcast address and store
++                       * the port GUID into the hardware address.
++                       */
++                      if (ifa->ifa_flags & IFF_BROADCAST) {
++                              struct sockaddr_ll *bll;
++
++                              bll = (struct sockaddr_ll *)ifa->ifa_broadaddr;
++                              memcpy(&info->bcast_addr, bll->sll_addr, 20);
++                      } else {
++                              memcpy(&info->bcast_addr, default_ib_bcast_addr,
++                                     20);
++                      }
++
++                      hw->hlen = 1;
++                      hw->hbuf[0] = HTYPE_INFINIBAND;
+                       break;
+ #if defined(ARPHRD_PPP)
+               case ARPHRD_PPP:
+                       if (local_family != AF_INET6)
+-                              log_fatal("Unsupported device type %d for \"%s\"",
+-                                         sa->sa_family, name);
++                              log_fatal("Unsupported device type %ld for \"%s\"",
++                                        (long int)sll->sll_family, name);
+                       hw->hlen = 0;
+                       hw->hbuf[0] = HTYPE_RESERVED;
+                       /* 0xdeadbeef should never occur on the wire,
+@@ -520,10 +678,11 @@ get_hw_addr(const char *name, struct har
+                       break;
+ #endif
+               default:
++                      freeifaddrs(ifaddrs);
+                       log_fatal("Unsupported device type %ld for \"%s\"",
+-                                (long int)sa->sa_family, name);
++                                (long int)sll->sll_family, name);
+       }
+-      close(sock);
++      freeifaddrs(ifaddrs);
+ }
+ #endif
+diff -up dhcp-4.2.2/common/socket.c.lpf-ib dhcp-4.2.2/common/socket.c
+--- dhcp-4.2.2/common/socket.c.lpf-ib  2011-06-27 18:18:20.000000000 +0200
++++ dhcp-4.2.2/common/socket.c 2011-09-19 11:24:08.705775490 +0200
+@@ -324,7 +324,7 @@ void if_register_send (info)
+       info->wfdesc = if_register_socket(info, AF_INET, 0);
+       /* If this is a normal IPv4 address, get the hardware address. */
+       if (strcmp(info->name, "fallback") != 0)
+-              get_hw_addr(info->name, &info->hw_address);
++              get_hw_addr(info);
+ #if defined (USE_SOCKET_FALLBACK)
+       /* Fallback only registers for send, but may need to receive as
+          well. */
+@@ -387,7 +387,7 @@ void if_register_receive (info)
+ #endif /* IP_PKTINFO... */
+       /* If this is a normal IPv4 address, get the hardware address. */
+       if (strcmp(info->name, "fallback") != 0)
+-              get_hw_addr(info->name, &info->hw_address);
++              get_hw_addr(info);
+       if (!quiet_interface_discovery)
+               log_info ("Listening on Socket/%s%s%s",
+@@ -497,7 +497,7 @@ if_register6(struct interface_info *info
+       if (req_multi)
+               if_register_multicast(info);
+-      get_hw_addr(info->name, &info->hw_address);
++      get_hw_addr(info);
+       if (!quiet_interface_discovery) {
+               if (info->shared_network != NULL) {
+diff -up dhcp-4.2.2/includes/dhcpd.h.lpf-ib dhcp-4.2.2/includes/dhcpd.h
+--- dhcp-4.2.2/includes/dhcpd.h.lpf-ib 2011-09-19 11:24:08.696775721 +0200
++++ dhcp-4.2.2/includes/dhcpd.h        2011-09-19 11:24:08.707775438 +0200
+@@ -1243,6 +1243,7 @@ struct interface_info {
+       struct shared_network *shared_network;
+                               /* Networks connected to this interface. */
+       struct hardware hw_address;     /* Its physical address. */
++      u_int8_t bcast_addr[20];        /* Infiniband broadcast address */
+       struct in_addr *addresses;      /* Addresses associated with this
+                                        * interface.
+                                        */
+@@ -2356,7 +2357,7 @@ void print_dns_status (int, struct dhcp_
+ #endif
+ const char *print_time(TIME);
+-void get_hw_addr(const char *name, struct hardware *hw);
++void get_hw_addr(struct interface_info *info);
+ /* socket.c */
+ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \
+diff -up dhcp-4.2.2/includes/dhcp.h.lpf-ib dhcp-4.2.2/includes/dhcp.h
+--- dhcp-4.2.2/includes/dhcp.h.lpf-ib  2011-09-19 11:24:08.696775721 +0200
++++ dhcp-4.2.2/includes/dhcp.h 2011-09-19 11:24:08.707775438 +0200
+@@ -79,6 +79,7 @@ struct dhcp_packet {
+ #define HTYPE_ETHER   1               /* Ethernet 10Mbps              */
+ #define HTYPE_IEEE802 6               /* IEEE 802.2 Token Ring...     */
+ #define HTYPE_FDDI    8               /* FDDI...                      */
++#define HTYPE_INFINIBAND 32           /* Infiniband IPoIB             */
+ #define HTYPE_RESERVED  0               /* RFC 5494 */
diff --git a/src/patches/dhcp-4.2.2-options.patch b/src/patches/dhcp-4.2.2-options.patch
new file mode 100644 (file)
index 0000000..32e2add
--- /dev/null
@@ -0,0 +1,401 @@
+diff -up dhcp-4.2.2b1/client/clparse.c.options dhcp-4.2.2b1/client/clparse.c
+--- dhcp-4.2.2b1/client/clparse.c.options      2011-04-21 16:08:14.000000000 +0200
++++ dhcp-4.2.2b1/client/clparse.c      2011-07-01 13:51:52.935755570 +0200
+@@ -146,6 +146,7 @@ isc_result_t read_client_conf ()
+       /* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
+        */
+       top_level_config.requested_lease = 7200;
++      top_level_config.bootp_broadcast_always = 0;
+       group_allocate (&top_level_config.on_receipt, MDL);
+       if (!top_level_config.on_receipt)
+@@ -313,7 +314,8 @@ void read_client_leases ()
+       interface-declaration |
+       LEASE client-lease-statement |
+       ALIAS client-lease-statement |
+-      KEY key-definition */
++      KEY key-definition |
++      BOOTP_BROADCAST_ALWAYS */
+ void parse_client_statement (cfile, ip, config)
+       struct parse *cfile;
+@@ -732,6 +734,12 @@ void parse_client_statement (cfile, ip, 
+               parse_reject_statement (cfile, config);
+               return;
++            case BOOTP_BROADCAST_ALWAYS:
++              token = next_token(&val, (unsigned*)0, cfile);
++              config -> bootp_broadcast_always = 1;
++              parse_semi (cfile);
++              return;
++
+             default:
+               lose = 0;
+               stmt = (struct executable_statement *)0;
+diff -up dhcp-4.2.2b1/client/dhclient.c.options dhcp-4.2.2b1/client/dhclient.c
+--- dhcp-4.2.2b1/client/dhclient.c.options     2011-05-11 16:20:59.000000000 +0200
++++ dhcp-4.2.2b1/client/dhclient.c     2011-07-01 13:51:52.936755545 +0200
+@@ -39,6 +39,12 @@
+ #include <limits.h>
+ #include <dns/result.h>
++/*
++ * Defined in stdio.h when _GNU_SOURCE is set, but we don't want to define
++ * that when building ISC code.
++ */
++extern int asprintf(char **strp, const char *fmt, ...);
++
+ TIME default_lease_time = 43200; /* 12 hours... */
+ TIME max_lease_time = 86400; /* 24 hours... */
+@@ -87,6 +93,9 @@ int wanted_ia_na = -1;               /* the absolute 
+ int wanted_ia_ta = 0;
+ int wanted_ia_pd = 0;
+ char *mockup_relay = NULL;
++int bootp_broadcast_always = 0;
++
++extern u_int32_t default_requested_options[];
+ void run_stateless(int exit_mode);
+@@ -123,6 +132,15 @@ main(int argc, char **argv) {
+       int local_family_set = 0;
+ #endif /* DHCPv6 */
+       char *s;
++      char *dhcp_client_identifier_arg = NULL;
++      char *dhcp_host_name_arg = NULL;
++      char *dhcp_fqdn_arg = NULL;
++      char *dhcp_vendor_class_identifier_arg = NULL;
++      char *dhclient_request_options = NULL;
++
++      int timeout_arg = 0;
++      char *arg_conf = NULL;
++      int arg_conf_len = 0;
+       /* Initialize client globals. */
+       memset(&default_duid, 0, sizeof(default_duid));
+@@ -310,6 +328,88 @@ main(int argc, char **argv) {
+               } else if (!strcmp(argv[i], "--version")) {
+                       log_info("isc-dhclient-%s", PACKAGE_VERSION);
+                       exit(0);
++              } else if (!strcmp(argv[i], "-I")) {
++                      if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++                              usage();
++                              exit(1);
++                      }
++
++                      if (strlen(argv[i]) >= DHCP_MAX_OPTION_LEN) {
++                              log_error("-I option dhcp-client-identifier string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_MAX_OPTION_LEN-1);
++                              exit(1);
++                      }
++
++                      dhcp_client_identifier_arg = argv[i];
++              } else if (!strcmp(argv[i], "-B")) {
++                      bootp_broadcast_always = 1;
++              } else if (!strcmp(argv[i], "-H")) {
++                      if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++                              usage();
++                              exit(1);
++                      }
++
++                      if (strlen(argv[i]) >= DHCP_MAX_OPTION_LEN) {
++                              log_error("-H option host-name string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_MAX_OPTION_LEN-1);
++                              exit(1);
++                      }
++
++                      if (dhcp_host_name_arg != NULL) {
++                              log_error("The -H <host-name> and -F <fqdn> arguments are mutually exclusive");
++                              exit(1);
++                      }
++
++                      dhcp_host_name_arg = argv[i];
++              } else if (!strcmp(argv[i], "-F")) {
++                      if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++                              usage();
++                              exit(1);
++                      }
++
++                      if (strlen(argv[i]) >= DHCP_MAX_OPTION_LEN) {
++                              log_error("-F option fqdn.fqdn string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_MAX_OPTION_LEN-1);
++                              exit(1);
++                      }
++
++                      if (dhcp_fqdn_arg != NULL) {
++                              log_error("Only one -F <fqdn> argument can be specified");
++                              exit(1);
++                      }
++
++                      if (dhcp_host_name_arg != NULL) {
++                              log_error("The -F <fqdn> and -H <host-name> arguments are mutually exclusive");
++                              exit(1);
++                      }
++
++                      dhcp_fqdn_arg = argv[i];
++              } else if (!strcmp(argv[i], "-timeout")) {
++                      if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++                              usage();
++                              exit(1);
++                      }
++
++                      if ((timeout_arg = atoi(argv[i])) <= 0) {
++                              log_error("-T timeout option must be > 0 - bad value: %s",argv[i]);
++                              exit(1);
++                      }
++              } else if (!strcmp(argv[i], "-V")) {
++                      if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++                              usage();
++                              exit(1);
++                      }
++
++                      if (strlen(argv[i]) >= DHCP_MAX_OPTION_LEN) {
++                              log_error("-V option vendor-class-identifier string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_MAX_OPTION_LEN-1);
++                              exit(1);
++                      }
++
++                      dhcp_vendor_class_identifier_arg = argv[i];
++              } else if (!strcmp(argv[i], "-R")) {
++                      if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++                              usage();
++                              exit(1);
++                      }
++
++                      dhclient_request_options = argv[i];
+               } else if (argv[i][0] == '-') {
+                   usage();
+               } else if (interfaces_requested < 0) {
+@@ -484,6 +584,166 @@ main(int argc, char **argv) {
+       /* Parse the dhclient.conf file. */
+       read_client_conf();
++      /* Parse any extra command line configuration arguments: */
++      if ((dhcp_client_identifier_arg != NULL) && (*dhcp_client_identifier_arg != '\0')) {
++              arg_conf_len = asprintf(&arg_conf, "send dhcp-client-identifier \"%s\";", dhcp_client_identifier_arg);
++
++              if ((arg_conf == 0) || (arg_conf_len <= 0))
++                      log_fatal("Unable to send -I option dhcp-client-identifier");
++      }
++
++      if ((dhcp_host_name_arg != NULL) && (*dhcp_host_name_arg != '\0')) {
++              if (arg_conf == 0) {
++                      arg_conf_len = asprintf(&arg_conf, "send host-name \"%s\";", dhcp_host_name_arg);
++
++                      if ((arg_conf == 0) || (arg_conf_len <= 0))
++                              log_fatal("Unable to send -H option host-name");
++              } else {
++                      char *last_arg_conf = arg_conf;
++                      arg_conf = NULL;
++                      arg_conf_len = asprintf(&arg_conf, "%s\nsend host-name \"%s\";", last_arg_conf, dhcp_host_name_arg);
++
++                      if ((arg_conf == 0) || (arg_conf_len <= 0))
++                              log_fatal("Unable to send -H option host-name");
++
++                      free(last_arg_conf);
++              }
++      }
++
++      if ((dhcp_fqdn_arg != NULL) && (*dhcp_fqdn_arg != '\0')) {
++              if (arg_conf == 0) {
++                      arg_conf_len = asprintf(&arg_conf,  "send fqdn.fqdn \"%s\";", dhcp_fqdn_arg);
++
++                      if ((arg_conf == 0) || (arg_conf_len <= 0))
++                              log_fatal("Unable to send -F option fqdn.fqdn");
++              } else {
++                      char *last_arg_conf = arg_conf;
++                      arg_conf = NULL;
++                      arg_conf_len = asprintf(&arg_conf, "%s\nsend fqdn.fqdn \"%s\";", last_arg_conf, dhcp_fqdn_arg);
++
++                      if ((arg_conf == 0)  || (arg_conf_len <= 0))
++                              log_fatal("Unable to send -F option fqdn.fqdn");
++
++                      free(last_arg_conf);
++              }
++      }
++
++      if (timeout_arg) {
++              if (arg_conf == 0) {
++                      arg_conf_len = asprintf(&arg_conf,  "timeout %d;", timeout_arg);
++
++                      if ((arg_conf == 0) || (arg_conf_len <= 0))
++                              log_fatal("Unable to process -timeout timeout argument");
++              } else {
++                      char *last_arg_conf = arg_conf;
++                      arg_conf = NULL;
++                      arg_conf_len = asprintf(&arg_conf, "%s\ntimeout %d;", last_arg_conf, timeout_arg);
++
++                      if ((arg_conf == 0) || (arg_conf_len == 0))
++                              log_fatal("Unable to process -timeout timeout argument");
++
++                      free(last_arg_conf);
++              }
++      }
++
++      if ((dhcp_vendor_class_identifier_arg != NULL) && (*dhcp_vendor_class_identifier_arg != '\0')) {
++              if (arg_conf == 0) {
++                      arg_conf_len = asprintf(&arg_conf,  "send vendor-class-identifier \"%s\";", dhcp_vendor_class_identifier_arg);
++
++                      if ((arg_conf == 0) || (arg_conf_len <= 0))
++                              log_fatal("Unable to send -V option vendor-class-identifier");
++              } else {
++                      char *last_arg_conf = arg_conf;
++                      arg_conf = NULL;
++                      arg_conf_len = asprintf(&arg_conf, "%s\nsend vendor-class-identifier \"%s\";", last_arg_conf, dhcp_vendor_class_identifier_arg);
++
++                      if ((arg_conf == 0) || (arg_conf_len <= 0))
++                              log_fatal("Unable to send -V option vendor-class-identifier");
++
++                      free(last_arg_conf);
++              }
++      }
++
++      if (dhclient_request_options != NULL) {
++              if (arg_conf == 0) {
++                      arg_conf_len = asprintf(&arg_conf,  "request %s;", dhclient_request_options);
++
++                      if ((arg_conf == 0) || (arg_conf_len <= 0))
++                              log_fatal("Unable to parse -R <request options list> argument");
++              } else {
++                      char *last_arg_conf = arg_conf;
++                      arg_conf = NULL;
++                      arg_conf_len = asprintf(&arg_conf, "%s\nrequest %s;", last_arg_conf, dhclient_request_options);
++
++                      if ((arg_conf == 0)  || (arg_conf_len <= 0))
++                              log_fatal("Unable to parse -R <request options list> argument");
++
++                      free(last_arg_conf);
++              }
++      }
++
++      if (arg_conf) {
++              if (arg_conf_len == 0)
++                      if ((arg_conf_len = strlen(arg_conf)) == 0)
++                              /* huh ? cannot happen ! */
++                              log_fatal("Unable to process -I/-H/-F/-timeout/-V/-R configuration arguments");
++
++              /* parse the extra dhclient.conf configuration arguments
++               * into top level config: */
++              struct parse *cfile = (struct parse *)0;
++              const char *val = NULL;
++              int token;
++
++              status = new_parse(&cfile, -1, arg_conf, arg_conf_len, "extra dhclient -I/-H/-F/-timeout/-V/-R configuration arguments", 0);
++
++              if ((status != ISC_R_SUCCESS) || (cfile -> warnings_occurred))
++                      log_fatal("Cannot parse -I/-H/-F/-timeout/-V/-R configuration arguments !");
++              /* more detailed parse failures will be logged */
++
++              do {
++                      token = peek_token(&val, (unsigned *)0, cfile);
++                      if (token == END_OF_FILE)
++                              break;
++
++                      parse_client_statement(cfile, (struct interface_info *)0, &top_level_config);
++              } while (1);
++
++              if (cfile -> warnings_occurred)
++                      log_fatal("Cannot parse -I/-H/-F/-timeout/-V/-R configuration arguments !");
++              end_parse(&cfile);
++
++              if (timeout_arg) {
++                      /* we just set the toplevel timeout, but per-client
++                       * timeouts may still be at defaults. Also, it makes no
++                       * sense having the reboot_timeout or backoff_cutoff
++                       * greater than the timeout:
++                       */
++                      if ((top_level_config.backoff_cutoff == 15) && (top_level_config.backoff_cutoff > (timeout_arg / 2)))
++                              top_level_config.backoff_cutoff = (((unsigned long)(timeout_arg / 2)) == 0) ? timeout_arg : (unsigned long)(timeout_arg / 2);
++
++                      for (ip=interfaces; ip; ip = ip->next) {
++                              if (ip->client->config->timeout == 60)
++                                      ip->client->config->timeout = timeout_arg;
++
++                              if ((ip->client->config->reboot_timeout == 10) && (ip->client->config->reboot_timeout > ip->client->config->timeout))
++                                      ip->client->config->reboot_timeout = ip->client->config->timeout;
++                              if ((ip->client->config->backoff_cutoff == 15) && (ip->client->config->backoff_cutoff > top_level_config.backoff_cutoff))
++                                      ip->client->config->backoff_cutoff = top_level_config.backoff_cutoff;
++                      }
++              }
++
++              if ((dhclient_request_options != 0) && (top_level_config.requested_options != default_requested_options)) {
++                      for (ip=interfaces; ip; ip = ip->next) {
++                              if (ip->client->config->requested_options == default_requested_options)
++                                      ip->client->config->requested_options = top_level_config.requested_options;
++                      }
++              }
++
++              free(arg_conf);
++              arg_conf = NULL;
++              arg_conf_len = 0;
++      }
++
+       /* Parse the lease database. */
+       read_client_leases();
+@@ -2397,7 +2657,8 @@ void make_discover (client, lease)
+       client -> packet.xid = random ();
+       client -> packet.secs = 0; /* filled in by send_discover. */
+-      if (can_receive_unicast_unconfigured (client -> interface))
++      if ((!(bootp_broadcast_always || client->config->bootp_broadcast_always))
++          && can_receive_unicast_unconfigured(client->interface))
+               client -> packet.flags = 0;
+       else
+               client -> packet.flags = htons (BOOTP_BROADCAST);
+@@ -2481,7 +2742,9 @@ void make_request (client, lease)
+       } else {
+               memset (&client -> packet.ciaddr, 0,
+                       sizeof client -> packet.ciaddr);
+-              if (can_receive_unicast_unconfigured (client -> interface))
++              if ((!(bootp_broadcast_always ||
++                  client ->config->bootp_broadcast_always)) &&
++                  can_receive_unicast_unconfigured (client -> interface))
+                       client -> packet.flags = 0;
+               else
+                       client -> packet.flags = htons (BOOTP_BROADCAST);
+@@ -2543,7 +2806,8 @@ void make_decline (client, lease)
+       client -> packet.hops = 0;
+       client -> packet.xid = client -> xid;
+       client -> packet.secs = 0; /* Filled in by send_request. */
+-      if (can_receive_unicast_unconfigured (client -> interface))
++      if ((!(bootp_broadcast_always || client->config-> bootp_broadcast_always))
++          && can_receive_unicast_unconfigured (client->interface))
+               client -> packet.flags = 0;
+       else
+               client -> packet.flags = htons (BOOTP_BROADCAST);
+diff -up dhcp-4.2.2b1/common/conflex.c.options dhcp-4.2.2b1/common/conflex.c
+--- dhcp-4.2.2b1/common/conflex.c.options      2011-05-11 16:20:59.000000000 +0200
++++ dhcp-4.2.2b1/common/conflex.c      2011-07-01 13:51:52.938755494 +0200
+@@ -808,6 +808,8 @@ intern(char *atom, enum dhcp_token dfv) 
+                       return BALANCE;
+               if (!strcasecmp (atom + 1, "ound"))
+                       return BOUND;
++              if (!strcasecmp (atom + 1, "ootp-broadcast-always"))
++                      return BOOTP_BROADCAST_ALWAYS;
+               break;
+             case 'c':
+               if (!strcasecmp(atom + 1, "ase"))
+diff -up dhcp-4.2.2b1/includes/dhcpd.h.options dhcp-4.2.2b1/includes/dhcpd.h
+--- dhcp-4.2.2b1/includes/dhcpd.h.options      2011-05-20 16:21:11.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhcpd.h      2011-07-01 13:51:52.940755442 +0200
+@@ -1147,6 +1147,9 @@ struct client_config {
+       int do_forward_update;          /* If nonzero, and if we have the
+                                          information we need, update the
+                                          A record for the address we get. */
++
++      int bootp_broadcast_always;     /* If nonzero, always set the BOOTP_BROADCAST
++                                         flag in requests */
+ };
+ /* Per-interface state used in the dhcp client... */
+diff -up dhcp-4.2.2b1/includes/dhctoken.h.options dhcp-4.2.2b1/includes/dhctoken.h
+--- dhcp-4.2.2b1/includes/dhctoken.h.options   2011-05-12 14:02:47.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhctoken.h   2011-07-01 13:53:43.316861637 +0200
+@@ -361,7 +361,8 @@ enum dhcp_token {
+       GETHOSTNAME = 662,
+       REWIND = 663,
+       INITIAL_DELAY = 664,
+-      GETHOSTBYNAME = 665
++      GETHOSTBYNAME = 665,
++      BOOTP_BROADCAST_ALWAYS = 666
+ };
+ #define is_identifier(x)      ((x) >= FIRST_TOKEN &&  \
diff --git a/src/patches/dhcp-4.2.2-remove-bind.patch b/src/patches/dhcp-4.2.2-remove-bind.patch
new file mode 100644 (file)
index 0000000..6297772
--- /dev/null
@@ -0,0 +1,149 @@
+diff -up dhcp-4.2.2/client/Makefile.am.rh637017 dhcp-4.2.2/client/Makefile.am
+--- dhcp-4.2.2/client/Makefile.am.rh637017     2010-09-15 00:32:36.000000000 +0200
++++ dhcp-4.2.2/client/Makefile.am      2011-08-11 17:28:58.923897561 +0200
+@@ -5,7 +5,7 @@ dhclient_SOURCES = clparse.c dhclient.c 
+                  scripts/netbsd scripts/nextstep scripts/openbsd \
+                  scripts/solaris scripts/openwrt
+ dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+-               ../bind/lib/libdns.a ../bind/lib/libisc.a
++               $(BIND9_LIBDIR) -ldns-export -lisc-export
+ man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
+ EXTRA_DIST = $(man_MANS)
+diff -up dhcp-4.2.2/common/tests/Makefile.am.rh637017 dhcp-4.2.2/common/tests/Makefile.am
+--- dhcp-4.2.2/common/tests/Makefile.am.rh637017       2009-10-28 05:12:30.000000000 +0100
++++ dhcp-4.2.2/common/tests/Makefile.am        2011-08-11 17:33:45.258637236 +0200
+@@ -6,6 +6,5 @@ TESTS = test_alloc
+ test_alloc_SOURCES = test_alloc.c
+ test_alloc_LDADD = ../libdhcp.a ../../tests/libt_api.a \
+-      ../../omapip/libomapi.a ../../bind/lib/libdns.a \
+-        ../../bind/lib/libisc.a
+-
++      ../../omapip/libomapi.a \
++       $(BIND9_LIBDIR) -ldns-export -lisc-export
+diff -up dhcp-4.2.2/configure.ac.rh637017 dhcp-4.2.2/configure.ac
+--- dhcp-4.2.2/configure.ac.rh637017   2011-07-20 02:32:18.000000000 +0200
++++ dhcp-4.2.2/configure.ac    2011-08-11 17:28:58.924897535 +0200
+@@ -512,20 +512,37 @@ AC_CHECK_MEMBER(struct msghdr.msg_contro
+ libbind=
+ AC_ARG_WITH(libbind,
+       AC_HELP_STRING([--with-libbind=PATH],
+-                     [bind includes and libraries are in PATH 
+-                      (default is ./bind)]),
++                     [bind includes are in PATH 
++                      (default is ./bind/includes)]),
+       use_libbind="$withval", use_libbind="no")
+ case "$use_libbind" in 
++yes|no)
++      libbind="\${top_srcdir}/bind/include"
++      ;;
++*)
++      libbind="$use_libbind"
++      ;;
++esac
++
++BIND9_LIBDIR='-L$(top_builddir)/bind/lib'
++AC_ARG_WITH(libbind-libs,
++      AC_HELP_STRING([--with-libbind-libs=PATH],
++                     [bind9 export libraries are in PATH]),
++                     [libbind_libs="$withval"], [libbind_libs='no'])
++case "$libbind_libs" in
+ yes)
+-      libbind="\${top_srcdir}/bind"
++      AC_MSG_ERROR([Specify path to bind9 libraries])
+       ;;
+ no)
+-      libbind="\${top_srcdir}/bind"
++      BUNDLED_BIND=yes
+       ;;
+ *)
+-      libbind="$use_libbind"
++      BIND9_LIBDIR="-L$libbind_libs"
++      BUNDLED_BIND=no
+       ;;
+ esac
++AM_CONDITIONAL([BUNDLED_BIND], [test "$BUNDLED_BIND" = yes])
++AC_SUBST([BIND9_LIBDIR])
+ # OpenLDAP support.
+ AC_ARG_WITH(ldap,
+@@ -562,7 +579,7 @@ fi
+ CFLAGS="$CFLAGS $STD_CWARNINGS"
+ # Try to add the bind include directory
+-CFLAGS="$CFLAGS -I$libbind/include"
++CFLAGS="$CFLAGS -I$libbind"
+ AC_C_FLEXIBLE_ARRAY_MEMBER
+diff -up dhcp-4.2.2/dhcpctl/Makefile.am.rh637017 dhcp-4.2.2/dhcpctl/Makefile.am
+--- dhcp-4.2.2/dhcpctl/Makefile.am.rh637017    2009-10-28 05:12:30.000000000 +0100
++++ dhcp-4.2.2/dhcpctl/Makefile.am     2011-08-11 17:28:58.924897535 +0200
+@@ -6,10 +6,10 @@ EXTRA_DIST = $(man_MANS)
+ omshell_SOURCES = omshell.c
+ omshell_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
+-              ../bind/lib/libdns.a ../bind/lib/libisc.a
++              $(BIND9_LIBDIR) -ldns-export -lisc-export
+ libdhcpctl_a_SOURCES = dhcpctl.c callback.c remote.c
+ cltest_SOURCES = cltest.c
+ cltest_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
+-             ../bind/lib/libdns.a ../bind/lib/libisc.a
+\ No newline at end of file
++             $(BIND9_LIBDIR) -ldns-export -lisc-export
+diff -up dhcp-4.2.2/Makefile.am.rh637017 dhcp-4.2.2/Makefile.am
+--- dhcp-4.2.2/Makefile.am.rh637017    2010-03-25 00:30:38.000000000 +0100
++++ dhcp-4.2.2/Makefile.am     2011-08-11 17:28:58.925897509 +0200
+@@ -21,7 +21,13 @@ EXTRA_DIST = RELNOTES LICENSE \
+            util/bindvar.sh \
+            bind/Makefile bind/bind.tar.gz bind/version.tmp 
+-SUBDIRS = bind includes tests common dst omapip client dhcpctl relay server
++if BUNDLED_BIND
++SUBDIRS = bind
++else
++SUBDIRS = 
++endif
++
++SUBDIRS += includes tests common dst omapip client dhcpctl relay server
+ nobase_include_HEADERS = dhcpctl/dhcpctl.h
+diff -up dhcp-4.2.2/omapip/Makefile.am.rh637017 dhcp-4.2.2/omapip/Makefile.am
+--- dhcp-4.2.2/omapip/Makefile.am.rh637017     2010-02-12 01:13:54.000000000 +0100
++++ dhcp-4.2.2/omapip/Makefile.am      2011-08-11 17:28:58.939897149 +0200
+@@ -10,5 +10,5 @@ man_MANS = omapi.3
+ EXTRA_DIST = $(man_MANS)
+ svtest_SOURCES = test.c
+-svtest_LDADD = libomapi.a ../bind/lib/libdns.a ../bind/lib/libisc.a
++svtest_LDADD = libomapi.a $(BIND9_LIBDIR) -ldns-export -lisc-export
+diff -up dhcp-4.2.2/relay/Makefile.am.rh637017 dhcp-4.2.2/relay/Makefile.am
+--- dhcp-4.2.2/relay/Makefile.am.rh637017      2009-10-28 05:12:30.000000000 +0100
++++ dhcp-4.2.2/relay/Makefile.am       2011-08-11 17:28:58.940897123 +0200
+@@ -3,7 +3,7 @@ AM_CPPFLAGS = -DLOCALSTATEDIR='"@localst
+ sbin_PROGRAMS = dhcrelay
+ dhcrelay_SOURCES = dhcrelay.c
+ dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+-               ../bind/lib/libdns.a ../bind/lib/libisc.a
++               $(BIND9_LIBDIR) -ldns-export -lisc-export
+ man_MANS = dhcrelay.8
+ EXTRA_DIST = $(man_MANS)
+diff -up dhcp-4.2.2/server/Makefile.am.rh637017 dhcp-4.2.2/server/Makefile.am
+--- dhcp-4.2.2/server/Makefile.am.rh637017     2010-03-24 22:49:47.000000000 +0100
++++ dhcp-4.2.2/server/Makefile.am      2011-08-11 17:28:58.944897021 +0200
+@@ -8,8 +8,7 @@ dhcpd_SOURCES = dhcpd.c dhcp.c bootp.c c
+ dhcpd_CFLAGS = $(LDAP_CFLAGS)
+ dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+-            ../dhcpctl/libdhcpctl.a ../bind/lib/libdns.a \
+-            ../bind/lib/libisc.a
++            ../dhcpctl/libdhcpctl.a $(BIND9_LIBDIR) -ldns-export -lisc-export
+ man_MANS = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
+ EXTRA_DIST = $(man_MANS)
diff --git a/src/patches/dhcp-4.2.2-rfc3442-classless-static-routes.patch b/src/patches/dhcp-4.2.2-rfc3442-classless-static-routes.patch
new file mode 100644 (file)
index 0000000..0a0bfcb
--- /dev/null
@@ -0,0 +1,405 @@
+diff -up dhcp-4.2.2b1/client/clparse.c.rfc3442 dhcp-4.2.2b1/client/clparse.c
+--- dhcp-4.2.2b1/client/clparse.c.rfc3442      2011-07-01 14:22:38.031534508 +0200
++++ dhcp-4.2.2b1/client/clparse.c      2011-07-01 14:22:38.128532940 +0200
+@@ -37,7 +37,7 @@
+ struct client_config top_level_config;
+-#define NUM_DEFAULT_REQUESTED_OPTS    14
++#define NUM_DEFAULT_REQUESTED_OPTS    15
+ struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
+ static void parse_client_default_duid(struct parse *cfile);
+@@ -82,7 +82,11 @@ isc_result_t read_client_conf ()
+                               dhcp_universe.code_hash, &code, 0, MDL);
+       /* 4 */
+-      code = DHO_ROUTERS;
++      /* The Classless Static Routes option code MUST appear in the parameter
++     * request list prior to both the Router option code and the Static
++     * Routes option code, if present. (RFC3442)
++       */
++      code = DHO_CLASSLESS_STATIC_ROUTES;
+       option_code_hash_lookup(&default_requested_options[3],
+                               dhcp_universe.code_hash, &code, 0, MDL);
+@@ -136,6 +140,11 @@ isc_result_t read_client_conf ()
+       option_code_hash_lookup(&default_requested_options[13],
+                               dhcp_universe.code_hash, &code, 0, MDL);
++      /* 15 */
++      code = DHO_ROUTERS;
++      option_code_hash_lookup(&default_requested_options[14],
++                              dhcp_universe.code_hash, &code, 0, MDL);
++
+       for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
+               if (default_requested_options[code] == NULL)
+                       log_fatal("Unable to find option definition for "
+diff -up dhcp-4.2.2b1/common/dhcp-options.5.rfc3442 dhcp-4.2.2b1/common/dhcp-options.5
+--- dhcp-4.2.2b1/common/dhcp-options.5.rfc3442 2011-07-01 14:22:38.020534686 +0200
++++ dhcp-4.2.2b1/common/dhcp-options.5 2011-07-01 14:22:38.129532924 +0200
+@@ -115,6 +115,26 @@ hexadecimal, separated by colons.   For 
+ or
+   option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f;
+ .fi
++.PP
++The
++.B destination-descriptor
++describe the IP subnet number and subnet mask
++of a particular destination using a compact encoding. This encoding
++consists of one octet describing the width of the subnet mask,
++followed by all the significant octets of the subnet number.
++The following table contains some examples of how various subnet
++number/mask combinations can be encoded:
++.nf
++.sp 1
++Subnet number   Subnet mask      Destination descriptor
++0               0                0
++10.0.0.0        255.0.0.0        8.10
++10.0.0.0        255.255.255.0    24.10.0.0
++10.17.0.0       255.255.0.0      16.10.17
++10.27.129.0     255.255.255.0    24.10.27.129
++10.229.0.128    255.255.255.128  25.10.229.0.128
++10.198.122.47   255.255.255.255  32.10.198.122.47
++.fi
+ .SH SETTING OPTION VALUES USING EXPRESSIONS
+ Sometimes it's helpful to be able to set the value of a DHCP option
+ based on some value that the client has sent.   To do this, you can
+@@ -931,6 +951,29 @@ dhclient-script will create routes:
+ .RE
+ .PP
+ .nf
++.B option \fBclassless-static-routes\fR \fIdestination-descriptor ip-address\fR
++                            [\fB,\fR \fIdestination-descriptor ip-address\fR...]\fB;\fR
++.fi
++.RS 0.25i
++.PP
++This option (see RFC3442) specifies a list of classless static routes
++that the client should install in its routing cache.
++.PP
++This option can contain one or more static routes, each of which
++consists of a destination descriptor and the IP address of the router
++that should be used to reach that destination.
++.PP
++Many clients may not implement the Classless Static Routes option.
++DHCP server administrators should therefore configure their DHCP
++servers to send both a Router option and a Classless Static Routes
++option, and should specify the default router(s) both in the Router
++option and in the Classless Static Routes option.
++.PP
++If the DHCP server returns both a Classless Static Routes option and
++a Router option, the DHCP client ignores the Router option.
++.RE
++.PP
++.nf
+ .B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR
+                                            [\fB,\fR \fIip-address\fR...]\fB;\fR
+ .fi
+diff -up dhcp-4.2.2b1/common/inet.c.rfc3442 dhcp-4.2.2b1/common/inet.c
+--- dhcp-4.2.2b1/common/inet.c.rfc3442 2011-05-11 02:47:22.000000000 +0200
++++ dhcp-4.2.2b1/common/inet.c 2011-07-01 14:22:38.130532908 +0200
+@@ -528,6 +528,60 @@ free_iaddrcidrnetlist(struct iaddrcidrne
+       return ISC_R_SUCCESS;
+ }
++static const char *
++inet_ntopdd(const unsigned char *src, unsigned srclen, char *dst, size_t size)
++{
++      char tmp[sizeof("32.255.255.255.255")];
++      int len;
++
++      switch (srclen) {
++              case 2:
++                      len = sprintf (tmp, "%u.%u", src[0], src[1]);
++                      break;
++              case 3:
++                      len = sprintf (tmp, "%u.%u.%u", src[0], src[1], src[2]);
++                      break;
++              case 4:
++                      len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
++                      break;
++              case 5:
++                      len = sprintf (tmp, "%u.%u.%u.%u.%u", src[0], src[1], src[2], src[3], src[4]);
++                      break;
++              default:
++                      return NULL;
++      }
++      if (len < 0)
++              return NULL;
++
++      if (len > size) {
++              errno = ENOSPC;
++              return NULL;
++      }
++
++      return strcpy (dst, tmp);
++}
++
++/* pdestdesc() turns an iaddr structure into a printable dest. descriptor */
++const char *
++pdestdesc(const struct iaddr addr) {
++      static char pbuf[sizeof("255.255.255.255.255")];
++
++      if (addr.len == 0) {
++              return "<null destination descriptor>";
++      }
++      if (addr.len == 1) {
++              return "0";
++      }
++      if ((addr.len >= 2) && (addr.len <= 5)) {
++              return inet_ntopdd(addr.iabuf, addr.len, pbuf, sizeof(pbuf));
++      }
++
++      log_fatal("pdestdesc():%s:%d: Invalid destination descriptor length %d.",
++                MDL, addr.len);
++      /* quell compiler warnings */
++      return NULL;
++}
++
+ /* piaddr() turns an iaddr structure into a printable address. */
+ /* XXX: should use a const pointer rather than passing the structure */
+ const char *
+diff -up dhcp-4.2.2b1/common/options.c.rfc3442 dhcp-4.2.2b1/common/options.c
+--- dhcp-4.2.2b1/common/options.c.rfc3442      2011-03-24 22:57:13.000000000 +0100
++++ dhcp-4.2.2b1/common/options.c      2011-07-01 14:22:38.132532876 +0200
+@@ -706,7 +706,11 @@ cons_options(struct packet *inpacket, st
+                * packet.
+                */
+               priority_list[priority_len++] = DHO_SUBNET_MASK;
+-              priority_list[priority_len++] = DHO_ROUTERS;
++              if (lookup_option(&dhcp_universe, cfg_options,
++                                                      DHO_CLASSLESS_STATIC_ROUTES))
++                      priority_list[priority_len++] = DHO_CLASSLESS_STATIC_ROUTES;
++              else
++                      priority_list[priority_len++] = DHO_ROUTERS;
+               priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS;
+               priority_list[priority_len++] = DHO_HOST_NAME;
+               priority_list[priority_len++] = DHO_FQDN;
+@@ -1683,6 +1687,7 @@ const char *pretty_print_option (option,
+       const unsigned char *dp = data;
+       char comma;
+       unsigned long tval;
++        unsigned int octets = 0;
+       if (emit_commas)
+               comma = ',';
+@@ -1691,6 +1696,7 @@ const char *pretty_print_option (option,
+       memset (enumbuf, 0, sizeof enumbuf);
++      if (option->format[0] != 'R') { /* see explanation lower */
+       /* Figure out the size of the data. */
+       for (l = i = 0; option -> format [i]; i++, l++) {
+               if (l >= sizeof(fmtbuf) - 1)
+@@ -1840,6 +1846,33 @@ const char *pretty_print_option (option,
+       if (numhunk < 0)
+               numhunk = 1;
++      } else { /* option->format[i] == 'R') */
++              /* R (destination descriptor) has variable length.
++               * We can find it only in classless static route option,
++               * so we are for sure parsing classless static route option now.
++               * We go through whole the option to check whether there are no
++               * missing/extra bytes.
++               * I didn't find out how to improve the existing code and that's the
++               * reason for this separate 'else' where I do my own checkings.
++               * I know it's little bit unsystematic, but it works.
++               */
++              numhunk = 0;
++              numelem = 2; /* RI */
++              fmtbuf[0]='R'; fmtbuf[1]='I'; fmtbuf[2]=0;
++              for (i =0; i < len; i = i + octets + 5) {
++                      if (data[i] > 32) { /* subnet mask width */
++                              log_error ("wrong subnet mask width in destination descriptor");
++                              break;
++                      }
++                      numhunk++;
++                      octets = ((data[i]+7) / 8);
++              }
++              if (i != len) {
++                      log_error ("classless static routes option has wrong size or "
++                                         "there's some garbage in format");
++              }
++      }
++
+       /* Cycle through the array (or hunk) printing the data. */
+       for (i = 0; i < numhunk; i++) {
+               for (j = 0; j < numelem; j++) {
+@@ -1978,6 +2011,20 @@ const char *pretty_print_option (option,
+                               strcpy(op, piaddr(iaddr));
+                               dp += 4;
+                               break;
++
++                            case 'R':
++                              if (dp[0] <= 32)
++                                      iaddr.len = (((dp[0]+7)/8)+1);
++                              else {
++                                      log_error ("wrong subnet mask width in destination descriptor");
++                                      return "<error>";
++                              }
++
++                              memcpy(iaddr.iabuf, dp, iaddr.len);
++                              strcpy(op, pdestdesc(iaddr));
++                              dp += iaddr.len;
++                              break;
++
+                             case '6':
+                               iaddr.len = 16;
+                               memcpy(iaddr.iabuf, dp, 16);
+diff -up dhcp-4.2.2b1/common/parse.c.rfc3442 dhcp-4.2.2b1/common/parse.c
+--- dhcp-4.2.2b1/common/parse.c.rfc3442        2011-07-01 14:22:38.097533441 +0200
++++ dhcp-4.2.2b1/common/parse.c        2011-07-01 14:22:38.135532828 +0200
+@@ -341,6 +341,39 @@ int parse_ip_addr (cfile, addr)
+ }     
+ /*
++ * destination-descriptor :== NUMBER DOT NUMBER |
++ *                            NUMBER DOT NUMBER DOT NUMBER |
++ *                            NUMBER DOT NUMBER DOT NUMBER DOT NUMBER |
++ *                            NUMBER DOT NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
++ */
++
++int parse_destination_descriptor (cfile, addr)
++      struct parse *cfile;
++      struct iaddr *addr;
++{
++              unsigned int mask_width, dest_dest_len;
++              addr -> len = 0;
++              if (parse_numeric_aggregate (cfile, addr -> iabuf,
++                                                                       &addr -> len, DOT, 10, 8)) {
++                      mask_width = (unsigned int)addr->iabuf[0];
++                      dest_dest_len = (((mask_width+7)/8)+1);
++                      if (mask_width > 32) {
++                              parse_warn (cfile,
++                              "subnet mask width (%u) greater than 32.", mask_width);
++                      }
++                      else if (dest_dest_len != addr->len) {
++                              parse_warn (cfile,
++                              "destination descriptor with subnet mask width %u "
++                              "should have %u octets, but has %u octets.",
++                              mask_width, dest_dest_len, addr->len);
++                      }
++
++                      return 1;
++              }
++              return 0;
++}
++
++/*
+  * Return true if every character in the string is hexadecimal.
+  */
+ static int
+@@ -700,8 +733,10 @@ unsigned char *parse_numeric_aggregate (
+               if (count) {
+                       token = peek_token (&val, (unsigned *)0, cfile);
+                       if (token != separator) {
+-                              if (!*max)
++                              if (!*max) {
++                                      *max = count;
+                                       break;
++                              }
+                               if (token != RBRACE && token != LBRACE)
+                                       token = next_token (&val,
+                                                           (unsigned *)0,
+@@ -1624,6 +1659,9 @@ int parse_option_code_definition (cfile,
+             case IP_ADDRESS:
+               type = 'I';
+               break;
++            case DESTINATION_DESCRIPTOR:
++              type = 'R';
++              break;
+             case IP6_ADDRESS:
+               type = '6';
+               break;
+@@ -5288,6 +5326,15 @@ int parse_option_token (rv, cfile, fmt, 
+               }
+               break;
++            case 'R': /* destination descriptor */
++              if (!parse_destination_descriptor (cfile, &addr)) {
++                      return 0;
++              }
++              if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1, MDL)) {
++                      return 0;
++              }
++              break;
++
+             case '6': /* IPv6 address. */
+               if (!parse_ip6_addr(cfile, &addr)) {
+                       return 0;
+@@ -5548,6 +5595,13 @@ int parse_option_decl (oc, cfile)
+                                       goto exit;
+                               len = ip_addr.len;
+                               dp = ip_addr.iabuf;
++                              goto alloc;
++
++                            case 'R': /* destination descriptor */
++                              if (!parse_destination_descriptor (cfile, &ip_addr))
++                                      goto exit;
++                              len = ip_addr.len;
++                              dp = ip_addr.iabuf;
+                             alloc:
+                               if (hunkix + len > sizeof hunkbuf) {
+diff -up dhcp-4.2.2b1/common/tables.c.rfc3442 dhcp-4.2.2b1/common/tables.c
+--- dhcp-4.2.2b1/common/tables.c.rfc3442       2011-07-01 14:22:38.087533601 +0200
++++ dhcp-4.2.2b1/common/tables.c       2011-07-01 14:22:38.137532796 +0200
+@@ -51,6 +51,7 @@ HASH_FUNCTIONS (option_code, const unsig
+    Format codes:
+    I - IPv4 address
++   R - destination descriptor (RFC3442)
+    6 - IPv6 address
+    l - 32-bit signed integer
+    L - 32-bit unsigned integer
+@@ -208,6 +209,7 @@ static struct option dhcp_options[] = {
+       { "default-url", "t",                   &dhcp_universe, 114, 1 },
+       { "subnet-selection", "I",              &dhcp_universe, 118, 1 },
+       { "domain-search", "D",         &dhcp_universe, 119, 1 },
++      { "classless-static-routes", "RIA",     &dhcp_universe, 121, 1 },
+       { "vivco", "Evendor-class.",            &dhcp_universe, 124, 1 },
+       { "vivso", "Evendor.",                  &dhcp_universe, 125, 1 },
+ #if 0
+diff -up dhcp-4.2.2b1/includes/dhcpd.h.rfc3442 dhcp-4.2.2b1/includes/dhcpd.h
+--- dhcp-4.2.2b1/includes/dhcpd.h.rfc3442      2011-07-01 14:22:38.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhcpd.h      2011-07-01 14:24:19.999810333 +0200
+@@ -2662,6 +2662,7 @@ isc_result_t range2cidr(struct iaddrcidr
+                       const struct iaddr *lo, const struct iaddr *hi);
+ isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result);
+ const char *piaddr (struct iaddr);
++const char *pdestdesc (struct iaddr);
+ char *piaddrmask(struct iaddr *, struct iaddr *);
+ char *piaddrcidr(const struct iaddr *, unsigned int);
+ u_int16_t validate_port(char *);
+@@ -2869,6 +2870,7 @@ void parse_client_lease_declaration (str
+ int parse_option_decl (struct option_cache **, struct parse *);
+ void parse_string_list (struct parse *, struct string_list **, int);
+ int parse_ip_addr (struct parse *, struct iaddr *);
++int parse_destination_descriptor (struct parse *, struct iaddr *);
+ int parse_ip_addr_with_subnet(struct parse *, struct iaddrmatch *);
+ void parse_reject_statement (struct parse *, struct client_config *);
+diff -up dhcp-4.2.2b1/includes/dhcp.h.rfc3442 dhcp-4.2.2b1/includes/dhcp.h
+--- dhcp-4.2.2b1/includes/dhcp.h.rfc3442       2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/includes/dhcp.h       2011-07-01 14:22:38.145532665 +0200
+@@ -158,6 +158,7 @@ struct dhcp_packet {
+ #define DHO_ASSOCIATED_IP                     92
+ #define DHO_SUBNET_SELECTION                  118 /* RFC3011! */
+ #define DHO_DOMAIN_SEARCH                     119 /* RFC3397 */
++#define DHO_CLASSLESS_STATIC_ROUTES           121 /* RFC3442 */
+ #define DHO_VIVCO_SUBOPTIONS                  124
+ #define DHO_VIVSO_SUBOPTIONS                  125
+diff -up dhcp-4.2.2b1/includes/dhctoken.h.rfc3442 dhcp-4.2.2b1/includes/dhctoken.h
+--- dhcp-4.2.2b1/includes/dhctoken.h.rfc3442   2011-07-01 14:22:37.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhctoken.h   2011-07-01 14:25:12.541867623 +0200
+@@ -362,7 +362,8 @@ enum dhcp_token {
+       REWIND = 663,
+       INITIAL_DELAY = 664,
+       GETHOSTBYNAME = 665,
+-      BOOTP_BROADCAST_ALWAYS = 666
++      BOOTP_BROADCAST_ALWAYS = 666,
++      DESTINATION_DESCRIPTOR = 667
+ };
+ #define is_identifier(x)      ((x) >= FIRST_TOKEN &&  \
diff --git a/src/patches/dhcp-4.2.2-sharedlib.patch b/src/patches/dhcp-4.2.2-sharedlib.patch
new file mode 100644 (file)
index 0000000..74fe9f1
--- /dev/null
@@ -0,0 +1,119 @@
+diff -up dhcp-4.2.2/client/Makefile.am.sharedlib dhcp-4.2.2/client/Makefile.am
+--- dhcp-4.2.2/client/Makefile.am.sharedlib    2011-09-09 16:35:56.000000000 +0200
++++ dhcp-4.2.2/client/Makefile.am      2011-09-09 16:36:29.849007951 +0200
+@@ -4,7 +4,7 @@ dhclient_SOURCES = clparse.c dhclient.c
+                  scripts/bsdos scripts/freebsd scripts/linux scripts/macos \
+                  scripts/netbsd scripts/nextstep scripts/openbsd \
+                  scripts/solaris scripts/openwrt
+-dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
++dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.la \
+                $(BIND9_LIBDIR) -ldns-export -lisc-export $(CAPNG_LDADD)
+ man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
+ EXTRA_DIST = $(man_MANS)
+diff -up dhcp-4.2.2/configure.ac.sharedlib dhcp-4.2.2/configure.ac
+--- dhcp-4.2.2/configure.ac.sharedlib  2011-09-09 16:35:56.097000001 +0200
++++ dhcp-4.2.2/configure.ac    2011-09-09 16:35:56.383000000 +0200
+@@ -30,7 +30,8 @@ fi
+ # Use this to define _GNU_SOURCE to pull in the IPv6 Advanced Socket API.
+ AC_USE_SYSTEM_EXTENSIONS
+-AC_PROG_RANLIB
++# Use libtool to simplify building of shared libraries
++AC_PROG_LIBTOOL
+ AC_CONFIG_HEADERS([includes/config.h])
+ # we sometimes need to know byte order for building packets
+diff -up dhcp-4.2.2/dhcpctl/Makefile.am.sharedlib dhcp-4.2.2/dhcpctl/Makefile.am
+--- dhcp-4.2.2/dhcpctl/Makefile.am.sharedlib   2011-09-09 16:35:55.459000001 +0200
++++ dhcp-4.2.2/dhcpctl/Makefile.am     2011-09-09 16:35:56.384000000 +0200
+@@ -1,15 +1,15 @@
+ bin_PROGRAMS = omshell
+-lib_LIBRARIES = libdhcpctl.a
++lib_LTLIBRARIES = libdhcpctl.la
+ noinst_PROGRAMS = cltest
+ man_MANS = omshell.1 dhcpctl.3
+ EXTRA_DIST = $(man_MANS)
+ omshell_SOURCES = omshell.c
+-omshell_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
++omshell_LDADD = libdhcpctl.la ../common/libdhcp.a ../omapip/libomapi.la \
+               $(BIND9_LIBDIR) -ldns-export -lisc-export
+-libdhcpctl_a_SOURCES = dhcpctl.c callback.c remote.c
++libdhcpctl_la_SOURCES = dhcpctl.c callback.c remote.c
+ cltest_SOURCES = cltest.c
+-cltest_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
++cltest_LDADD = libdhcpctl.la ../common/libdhcp.a ../omapip/libomapi.la \
+              $(BIND9_LIBDIR) -ldns-export -lisc-export
+diff -up dhcp-4.2.2/dst/base64.c.sharedlib dhcp-4.2.2/dst/base64.c
+--- dhcp-4.2.2/dst/base64.c.sharedlib  2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2/dst/base64.c    2011-09-09 16:35:56.385000000 +0200
+@@ -64,6 +64,7 @@ static const char rcsid[] = "$Id: base64
+ #include <sys/socket.h>
++#include "dst_internal.h"
+ #include "cdefs.h"
+ #include "osdep.h"
+ #include "arpa/nameser.h"
+diff -up dhcp-4.2.2/dst/Makefile.am.sharedlib dhcp-4.2.2/dst/Makefile.am
+--- dhcp-4.2.2/dst/Makefile.am.sharedlib       2007-05-29 18:32:10.000000000 +0200
++++ dhcp-4.2.2/dst/Makefile.am 2011-09-09 16:35:56.386000000 +0200
+@@ -1,8 +1,8 @@
+ AM_CPPFLAGS = -DMINIRES_LIB -DHMAC_MD5
+-lib_LIBRARIES = libdst.a
++lib_LTLIBRARIES = libdst.la
+-libdst_a_SOURCES = dst_support.c dst_api.c hmac_link.c md5_dgst.c \
++libdst_la_SOURCES = dst_support.c dst_api.c hmac_link.c md5_dgst.c \
+                  base64.c prandom.c
+ EXTRA_DIST = dst_internal.h md5.h md5_locl.h
+diff -up dhcp-4.2.2/omapip/Makefile.am.sharedlib dhcp-4.2.2/omapip/Makefile.am
+--- dhcp-4.2.2/omapip/Makefile.am.sharedlib    2011-09-09 16:35:55.000000000 +0200
++++ dhcp-4.2.2/omapip/Makefile.am      2011-09-09 16:37:36.734000324 +0200
+@@ -1,7 +1,7 @@
+-lib_LIBRARIES = libomapi.a
++lib_LTLIBRARIES = libomapi.la
+ noinst_PROGRAMS = svtest
+-libomapi_a_SOURCES = protocol.c buffer.c alloc.c result.c connection.c \
++libomapi_la_SOURCES = protocol.c buffer.c alloc.c result.c connection.c \
+                    errwarn.c listener.c dispatch.c generic.c support.c \
+                    handle.c message.c convert.c hash.c auth.c inet_addr.c \
+                    array.c trace.c toisc.c iscprint.c isclib.c
+@@ -10,5 +10,5 @@ man_MANS = omapi.3
+ EXTRA_DIST = $(man_MANS)
+ svtest_SOURCES = test.c
+-svtest_LDADD = libomapi.a $(BIND9_LIBDIR) -ldns-export -lisc-export
++svtest_LDADD = libomapi.la $(BIND9_LIBDIR) -ldns-export -lisc-export
+diff -up dhcp-4.2.2/relay/Makefile.am.sharedlib dhcp-4.2.2/relay/Makefile.am
+--- dhcp-4.2.2/relay/Makefile.am.sharedlib     2011-09-09 16:35:56.000000000 +0200
++++ dhcp-4.2.2/relay/Makefile.am       2011-09-09 16:37:57.058019749 +0200
+@@ -2,7 +2,7 @@ AM_CPPFLAGS = -DLOCALSTATEDIR='"@localst
+ sbin_PROGRAMS = dhcrelay
+ dhcrelay_SOURCES = dhcrelay.c
+-dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
++dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.la \
+                $(BIND9_LIBDIR) -ldns-export -lisc-export $(CAPNG_LDADD)
+ man_MANS = dhcrelay.8
+ EXTRA_DIST = $(man_MANS)
+diff -up dhcp-4.2.2/server/Makefile.am.sharedlib dhcp-4.2.2/server/Makefile.am
+--- dhcp-4.2.2/server/Makefile.am.sharedlib    2011-09-09 16:35:56.000000000 +0200
++++ dhcp-4.2.2/server/Makefile.am      2011-09-09 16:38:56.291004599 +0200
+@@ -7,8 +7,8 @@ dhcpd_SOURCES = dhcpd.c dhcp.c bootp.c c
+               dhcpv6.c mdb6.c ldap.c ldap_casa.c
+ dhcpd_CFLAGS = $(LDAP_CFLAGS)
+-dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+-            ../dhcpctl/libdhcpctl.a $(BIND9_LIBDIR) -ldns-export -lisc-export \
++dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.la \
++            ../dhcpctl/libdhcpctl.la $(BIND9_LIBDIR) -ldns-export -lisc-export \
+             $(CAPNG_LDADD)
+ man_MANS = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
diff --git a/src/patches/dhcp-4.2.2-xen-checksum.patch b/src/patches/dhcp-4.2.2-xen-checksum.patch
new file mode 100644 (file)
index 0000000..038d346
--- /dev/null
@@ -0,0 +1,249 @@
+diff -up dhcp-4.2.2b1/common/bpf.c.xen dhcp-4.2.2b1/common/bpf.c
+--- dhcp-4.2.2b1/common/bpf.c.xen      2009-11-20 02:48:59.000000000 +0100
++++ dhcp-4.2.2b1/common/bpf.c  2011-07-01 14:00:16.936959001 +0200
+@@ -485,7 +485,7 @@ ssize_t receive_packet (interface, buf, 
+               offset = decode_udp_ip_header (interface,
+                                              interface -> rbuf,
+                                              interface -> rbuf_offset,
+-                                             from, hdr.bh_caplen, &paylen);
++                                             from, hdr.bh_caplen, &paylen, 0);
+               /* If the IP or UDP checksum was bad, skip the packet... */
+               if (offset < 0) {
+diff -up dhcp-4.2.2b1/common/dlpi.c.xen dhcp-4.2.2b1/common/dlpi.c
+--- dhcp-4.2.2b1/common/dlpi.c.xen     2011-05-11 16:20:59.000000000 +0200
++++ dhcp-4.2.2b1/common/dlpi.c 2011-07-01 14:00:16.937958997 +0200
+@@ -693,7 +693,7 @@ ssize_t receive_packet (interface, buf, 
+       length -= offset;
+ #endif
+       offset = decode_udp_ip_header (interface, dbuf, bufix,
+-                                     from, length, &paylen);
++                                     from, length, &paylen, 0);
+       /*
+        * If the IP or UDP checksum was bad, skip the packet...
+diff -up dhcp-4.2.2b1/common/lpf.c.xen dhcp-4.2.2b1/common/lpf.c
+--- dhcp-4.2.2b1/common/lpf.c.xen      2011-05-10 16:38:58.000000000 +0200
++++ dhcp-4.2.2b1/common/lpf.c  2011-07-01 14:11:24.725748028 +0200
+@@ -29,19 +29,33 @@
+ #include "dhcpd.h"
+ #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
+ #include <sys/ioctl.h>
++#include <sys/socket.h>
+ #include <sys/uio.h>
+ #include <errno.h>
+ #include <asm/types.h>
+ #include <linux/filter.h>
+ #include <linux/if_ether.h>
++#include <linux/if_packet.h>
+ #include <netinet/in_systm.h>
+-#include <net/if_packet.h>
+ #include "includes/netinet/ip.h"
+ #include "includes/netinet/udp.h"
+ #include "includes/netinet/if_ether.h"
+ #include <net/if.h>
++#ifndef PACKET_AUXDATA
++#define PACKET_AUXDATA 8
++
++struct tpacket_auxdata
++{
++      __u32           tp_status;
++      __u32           tp_len;
++      __u32           tp_snaplen;
++      __u16           tp_mac;
++      __u16           tp_net;
++};
++#endif
++
+ /* Reinitializes the specified interface after an address change.   This
+    is not required for packet-filter APIs. */
+@@ -67,10 +81,14 @@ int if_register_lpf (info)
+       struct interface_info *info;
+ {
+       int sock;
+-      struct sockaddr sa;
++      union {
++              struct sockaddr_ll ll;
++              struct sockaddr common;
++      } sa;
++      struct ifreq ifr;
+       /* Make an LPF socket. */
+-      if ((sock = socket(PF_PACKET, SOCK_PACKET,
++      if ((sock = socket(PF_PACKET, SOCK_RAW,
+                          htons((short)ETH_P_ALL))) < 0) {
+               if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+                   errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+@@ -85,11 +103,17 @@ int if_register_lpf (info)
+               log_fatal ("Open a socket for LPF: %m");
+       }
++      memset (&ifr, 0, sizeof ifr);
++      strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name);
++      ifr.ifr_name[IFNAMSIZ-1] = '\0';
++      if (ioctl (sock, SIOCGIFINDEX, &ifr))
++              log_fatal ("Failed to get interface index: %m");
++
+       /* Bind to the interface name */
+       memset (&sa, 0, sizeof sa);
+-      sa.sa_family = AF_PACKET;
+-      strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data);
+-      if (bind (sock, &sa, sizeof sa)) {
++      sa.ll.sll_family = AF_PACKET;
++      sa.ll.sll_ifindex = ifr.ifr_ifindex;
++      if (bind (sock, &sa.common, sizeof sa)) {
+               if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+                   errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+                   errno == EAFNOSUPPORT || errno == EINVAL) {
+@@ -171,9 +195,18 @@ static void lpf_gen_filter_setup (struct
+ void if_register_receive (info)
+       struct interface_info *info;
+ {
++      int val;
++
+       /* Open a LPF device and hang it on this interface... */
+       info -> rfdesc = if_register_lpf (info);
++      val = 1;
++      if (setsockopt (info -> rfdesc, SOL_PACKET, PACKET_AUXDATA, &val,
++                      sizeof val) < 0) {
++              if (errno != ENOPROTOOPT)
++                      log_fatal ("Failed to set auxiliary packet data: %m");
++      }
++
+ #if defined (HAVE_TR_SUPPORT)
+       if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
+               lpf_tr_filter_setup (info);
+@@ -295,7 +328,6 @@ ssize_t send_packet (interface, packet, 
+       double hh [16];
+       double ih [1536 / sizeof (double)];
+       unsigned char *buf = (unsigned char *)ih;
+-      struct sockaddr_pkt sa;
+       int result;
+       int fudge;
+@@ -316,17 +348,7 @@ ssize_t send_packet (interface, packet, 
+                               (unsigned char *)raw, len);
+       memcpy (buf + ibufp, raw, len);
+-      /* For some reason, SOCK_PACKET sockets can't be connected,
+-         so we have to do a sentdo every time. */
+-      memset (&sa, 0, sizeof sa);
+-      sa.spkt_family = AF_PACKET;
+-      strncpy ((char *)sa.spkt_device,
+-               (const char *)interface -> ifp, sizeof sa.spkt_device);
+-      sa.spkt_protocol = htons(ETH_P_IP);
+-
+-      result = sendto (interface -> wfdesc,
+-                       buf + fudge, ibufp + len - fudge, 0, 
+-                       (const struct sockaddr *)&sa, sizeof sa);
++      result = write (interface -> wfdesc, buf + fudge, ibufp + len - fudge);
+       if (result < 0)
+               log_error ("send_packet: %m");
+       return result;
+@@ -343,14 +365,35 @@ ssize_t receive_packet (interface, buf, 
+ {
+       int length = 0;
+       int offset = 0;
++      int nocsum = 0;
+       unsigned char ibuf [1536];
+       unsigned bufix = 0;
+       unsigned paylen;
++      unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
++      struct iovec iov = {
++              .iov_base = ibuf,
++              .iov_len = sizeof ibuf,
++      };
++      struct msghdr msg = {
++              .msg_iov = &iov,
++              .msg_iovlen = 1,
++              .msg_control = cmsgbuf,
++              .msg_controllen = sizeof(cmsgbuf),
++      };
++      struct cmsghdr *cmsg;
+-      length = read (interface -> rfdesc, ibuf, sizeof ibuf);
++      length = recvmsg (interface -> rfdesc, &msg, 0);
+       if (length <= 0)
+               return length;
++      for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
++              if (cmsg->cmsg_level == SOL_PACKET &&
++                  cmsg->cmsg_type == PACKET_AUXDATA) {
++                      struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
++                      nocsum = aux->tp_status & TP_STATUS_CSUMNOTREADY;
++              }
++      }
++
+       bufix = 0;
+       /* Decode the physical header... */
+       offset = decode_hw_header (interface, ibuf, bufix, hfrom);
+@@ -367,7 +410,7 @@ ssize_t receive_packet (interface, buf, 
+       /* Decode the IP and UDP headers... */
+       offset = decode_udp_ip_header (interface, ibuf, bufix, from,
+-                                     (unsigned)length, &paylen);
++                                     (unsigned)length, &paylen, nocsum);
+       /* If the IP or UDP checksum was bad, skip the packet... */
+       if (offset < 0)
+diff -up dhcp-4.2.2b1/common/nit.c.xen dhcp-4.2.2b1/common/nit.c
+--- dhcp-4.2.2b1/common/nit.c.xen      2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/common/nit.c  2011-07-01 14:00:16.939958989 +0200
+@@ -369,7 +369,7 @@ ssize_t receive_packet (interface, buf, 
+       /* Decode the IP and UDP headers... */
+       offset = decode_udp_ip_header (interface, ibuf, bufix,
+-                                     from, length, &paylen);
++                                     from, length, &paylen, 0);
+       /* If the IP or UDP checksum was bad, skip the packet... */
+       if (offset < 0)
+diff -up dhcp-4.2.2b1/common/packet.c.xen dhcp-4.2.2b1/common/packet.c
+--- dhcp-4.2.2b1/common/packet.c.xen   2009-07-23 20:52:20.000000000 +0200
++++ dhcp-4.2.2b1/common/packet.c       2011-07-01 14:00:16.939958989 +0200
+@@ -211,7 +211,7 @@ ssize_t
+ decode_udp_ip_header(struct interface_info *interface,
+                    unsigned char *buf, unsigned bufix,
+                    struct sockaddr_in *from, unsigned buflen,
+-                   unsigned *rbuflen)
++                   unsigned *rbuflen, int nocsum)
+ {
+   unsigned char *data;
+   struct ip ip;
+@@ -322,7 +322,7 @@ decode_udp_ip_header(struct interface_in
+                                          8, IPPROTO_UDP + ulen))));
+   udp_packets_seen++;
+-  if (usum && usum != sum) {
++  if (!nocsum && usum && usum != sum) {
+         udp_packets_bad_checksum++;
+         if (udp_packets_seen > 4 &&
+             (udp_packets_seen / udp_packets_bad_checksum) < 2) {
+diff -up dhcp-4.2.2b1/common/upf.c.xen dhcp-4.2.2b1/common/upf.c
+--- dhcp-4.2.2b1/common/upf.c.xen      2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/common/upf.c  2011-07-01 14:00:16.940958986 +0200
+@@ -320,7 +320,7 @@ ssize_t receive_packet (interface, buf, 
+       /* Decode the IP and UDP headers... */
+       offset = decode_udp_ip_header (interface, ibuf, bufix,
+-                                     from, length, &paylen);
++                                     from, length, &paylen, 0);
+       /* If the IP or UDP checksum was bad, skip the packet... */
+       if (offset < 0)
+diff -up dhcp-4.2.2b1/includes/dhcpd.h.xen dhcp-4.2.2b1/includes/dhcpd.h
+--- dhcp-4.2.2b1/includes/dhcpd.h.xen  2011-07-01 14:00:16.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhcpd.h      2011-07-01 14:12:18.069642470 +0200
+@@ -2796,7 +2796,7 @@ ssize_t decode_hw_header (struct interfa
+                         unsigned, struct hardware *);
+ ssize_t decode_udp_ip_header (struct interface_info *, unsigned char *,
+                             unsigned, struct sockaddr_in *,
+-                            unsigned, unsigned *);
++                            unsigned, unsigned *, int);
+ /* ethernet.c */
+ void assemble_ethernet_header (struct interface_info *, unsigned char *,