[packages/dhcp] - updated to 4.4.3, more patches from Fedora

hawk hawk at pld-linux.org
Sun Apr 3 19:57:20 CEST 2022


commit 15c1a8319287edff43305ebc37c8b7fab896f48b
Author: Marcin Krol <hawk at tld-linux.org>
Date:   Sun Apr 3 17:56:37 2022 +0000

    - updated to 4.4.3, more patches from Fedora

 bind-detect-time-changes.patch               | 196 +++++++++
 bind-system-getaddrinfo.patch                | 117 +++++
 dhcp-CLOEXEC.patch                           | 366 ++++++++++++++++
 dhcp-add-guid-duid-to-logs.patch             | 327 ++++++++++++++
 dhcp-capabilities.patch                      | 266 ++++++++++++
 dhcp-client-request-release-bind-iface.patch |  76 ++++
 dhcp-confparse.patch                         |  56 +++
 dhcp-default-requested-options.patch         |  23 +-
 dhcp-detect-time-changes.patch               |  92 ++++
 dhcp-duid_uuid.patch                         | 125 ++++++
 dhcp-errwarn-message.patch                   |  21 +-
 dhcp-extravars.patch                         |  32 +-
 dhcp-garbage-in-format-string-error.patch    |  26 ++
 dhcp-handle-null-timouet.patch               |  31 ++
 dhcp-hwaddress.patch                         | 100 +++++
 dhcp-link-local-address.patch                |  79 ++++
 dhcp-lpf-ib.patch                            | 625 +++++++++++++++++++++++++++
 dhcp-manpages.patch                          | 144 ++++--
 dhcp-no-subnet-error2info.patch              |  62 +++
 dhcp-option97-pxe-client-id.patch            | 246 +++++++++++
 dhcp-options.patch                           | 241 ++++-------
 dhcp-paths.patch                             |  35 +-
 dhcp-ppp.patch                               | 175 ++++++++
 dhcp-release-by-ifup.patch                   |  29 +-
 dhcp-rfc3442-classless-static-routes.patch   | 436 +++++++++++++++++++
 dhcp-stateless-duid-llt.patch                |  28 ++
 dhcp-unicast-bootp.patch                     |  36 +-
 dhcp.spec                                    |  48 +-
 systemd-notify.patch                         |  35 +-
 29 files changed, 3792 insertions(+), 281 deletions(-)
---
diff --git a/dhcp.spec b/dhcp.spec
index e534e60..b98bb20 100644
--- a/dhcp.spec
+++ b/dhcp.spec
@@ -4,7 +4,7 @@
 %bcond_without	static_libs	# don't build static library
 %bcond_without	systemd		# without systemd units
 
-%define         ver     4.4.2
+%define         ver     4.4.3
 %if 0
 %define         pverdot .P1
 %define         pverdir -P1
@@ -26,7 +26,7 @@ Epoch:		4
 License:	MIT
 Group:		Networking/Daemons
 Source0:	ftp://ftp.isc.org/isc/dhcp/%{ver}%{pverdir}/%{name}-%{ver}%{pverdir}.tar.gz
-# Source0-md5:	2afdaf8498dc1edaf3012efdd589b3e1
+# Source0-md5:	9076af4cc1293dde5a7c6cae7de6ab45
 Source1:	%{name}.init
 Source2:	%{name}6.init
 Source3:	%{name}-relay.init
@@ -51,6 +51,25 @@ Patch8:		%{name}-default-requested-options.patch
 Patch9:		%{name}-manpages.patch
 Patch10:	%{name}-extravars.patch
 Patch11:	systemd-notify.patch
+Patch12:	%{name}-CLOEXEC.patch
+Patch13:	%{name}-garbage-in-format-string-error.patch
+Patch14:	%{name}-handle-null-timouet.patch
+Patch15:	%{name}-capabilities.patch
+Patch16:	%{name}-rfc3442-classless-static-routes.patch
+Patch17:	%{name}-ppp.patch
+Patch18:	%{name}-lpf-ib.patch
+Patch19:	%{name}-add-guid-duid-to-logs.patch
+Patch20:	%{name}-duid_uuid.patch
+Patch21:	%{name}-client-request-release-bind-iface.patch
+Patch22:	%{name}-no-subnet-error2info.patch
+Patch23:	%{name}-stateless-duid-llt.patch
+Patch24:	%{name}-hwaddress.patch
+Patch25:	%{name}-confparse.patch
+Patch26:	%{name}-link-local-address.patch
+Patch27:	%{name}-option97-pxe-client-id.patch
+Patch28:	%{name}-detect-time-changes.patch
+Patch29:	bind-detect-time-changes.patch
+Patch30:	bind-system-getaddrinfo.patch
 URL:		https://www.isc.org/dhcp/
 BuildRequires:	autoconf
 BuildRequires:	automake
@@ -217,6 +236,31 @@ komunikacji z działającym serwerem ISC DHCP i jego kontroli.
 %patch9 -p1
 %patch10 -p1
 %patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
+%patch17 -p1
+%patch18 -p1
+%patch19 -p1
+%patch20 -p1
+%patch21 -p1
+%patch22 -p1
+%patch23 -p1
+%patch24 -p1
+%patch25 -p1
+%patch26 -p1
+%patch27 -p1
+%patch28 -p1
+
+cd bind
+tar -xvf bind.tar.gz
+ln -s bind-9* bind
+cd ..
+
+%patch29 -p1
+%patch30 -p1
 
 # Copy in documentation and example scripts for LDAP patch to dhcpd
 cp -a %{SOURCE11} README.ldap
diff --git a/bind-detect-time-changes.patch b/bind-detect-time-changes.patch
new file mode 100644
index 0000000..5a26a6f
--- /dev/null
+++ b/bind-detect-time-changes.patch
@@ -0,0 +1,196 @@
+From 8e49f4b460ad20890c63a385c17d3e5decd45a82 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Tue, 22 Oct 2019 16:23:24 +0200
+Subject: [PATCH 25/28] bind: Detect system time changes
+
+---
+ .../bind-9.11.36/lib/isc/include/isc/result.h |  4 +-
+ bind/bind-9.11.36/lib/isc/include/isc/util.h  |  4 ++
+ bind/bind-9.11.36/lib/isc/result.c            |  2 +
+ bind/bind-9.11.36/lib/isc/unix/app.c          | 41 +++++++++++++++++--
+ .../lib/isc/unix/include/isc/time.h           | 20 +++++++++
+ bind/bind-9.11.36/lib/isc/unix/time.c         | 22 ++++++++++
+ 6 files changed, 89 insertions(+), 4 deletions(-)
+
+diff --git a/bind/bind-9.11.36/lib/isc/include/isc/result.h b/bind/bind-9.11.36/lib/isc/include/isc/result.h
+index 916641f..51c2468 100644
+--- a/bind/bind-9.11.36/lib/isc/include/isc/result.h
++++ b/bind/bind-9.11.36/lib/isc/include/isc/result.h
+@@ -89,7 +89,9 @@
+ #define ISC_R_DISCFULL			67	/*%< disc full */
+ #define ISC_R_DEFAULT			68	/*%< default */
+ #define ISC_R_IPV4PREFIX		69	/*%< IPv4 prefix */
+-#define ISC_R_NRESULTS 			70
++#define ISC_R_TIMESHIFTED               70      /*%< system time changed */
++/*% Not a result code: the number of results. */
++#define ISC_R_NRESULTS 			71
+ 
+ ISC_LANG_BEGINDECLS
+ 
+diff --git a/bind/bind-9.11.36/lib/isc/include/isc/util.h b/bind/bind-9.11.36/lib/isc/include/isc/util.h
+index 9111c2a..20a05b4 100644
+--- a/bind/bind-9.11.36/lib/isc/include/isc/util.h
++++ b/bind/bind-9.11.36/lib/isc/include/isc/util.h
+@@ -325,6 +325,10 @@ extern void mock_assert(const int result, const char* const expression,
+  * Time
+  */
+ #define TIME_NOW(tp) 	RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
++#ifdef CLOCK_BOOTTIME
++#define TIME_MONOTONIC(tp) 	RUNTIME_CHECK(isc_time_boottime((tp)) == ISC_R_SUCCESS)
++#endif
++
+ 
+ /*%
+  * Alignment
+diff --git a/bind/bind-9.11.36/lib/isc/result.c b/bind/bind-9.11.36/lib/isc/result.c
+index 887b08c..2106a3a 100644
+--- a/bind/bind-9.11.36/lib/isc/result.c
++++ b/bind/bind-9.11.36/lib/isc/result.c
+@@ -105,6 +105,7 @@ static const char *description[ISC_R_NRESULTS] = {
+ 	"disc full",				/*%< 67 */
+ 	"default",				/*%< 68 */
+ 	"IPv4 prefix",				/*%< 69 */
++        "time changed",                         /*%< 70 */
+ };
+ 
+ static const char *identifier[ISC_R_NRESULTS] = {
+@@ -178,6 +179,7 @@ static const char *identifier[ISC_R_NRESULTS] = {
+ 	"ISC_R_DISCFULL",
+ 	"ISC_R_DEFAULT",
+ 	"ISC_R_IPV4PREFIX",
++        "ISC_R_TIMESHIFTED",
+ };
+ 
+ #define ISC_RESULT_RESULTSET			2
+diff --git a/bind/bind-9.11.36/lib/isc/unix/app.c b/bind/bind-9.11.36/lib/isc/unix/app.c
+index 8189c63..4aabaa4 100644
+--- a/bind/bind-9.11.36/lib/isc/unix/app.c
++++ b/bind/bind-9.11.36/lib/isc/unix/app.c
+@@ -442,15 +442,51 @@ isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task,
+ static isc_result_t
+ evloop(isc__appctx_t *ctx) {
+ 	isc_result_t result;
++        isc_time_t now;
++#ifdef CLOCK_BOOTTIME
++        isc_time_t monotonic;
++        uint64_t diff  = 0;
++#else
++        isc_time_t prev;
++        TIME_NOW(&prev);
++#endif
++
++
++
+ 
+ 	while (!ctx->want_shutdown) {
+ 		int n;
+-		isc_time_t when, now;
++		isc_time_t when;
++                
+ 		struct timeval tv, *tvp;
+ 		isc_socketwait_t *swait;
+ 		bool readytasks;
+ 		bool call_timer_dispatch = false;
+ 
++                uint64_t us; 
++
++#ifdef CLOCK_BOOTTIME
++                // TBD macros for following three lines
++                TIME_NOW(&now);
++                TIME_MONOTONIC(&monotonic);
++                INSIST(now.seconds > monotonic.seconds)
++                us = isc_time_microdiff (&now, &monotonic);
++                if (us < diff){ 
++                  us = diff - us;
++                  if (us > 1000000){ // ignoring shifts less than one second
++                    return ISC_R_TIMESHIFTED;
++                  };
++                  diff = isc_time_microdiff (&now, &monotonic);
++                } else {
++                  diff = isc_time_microdiff (&now, &monotonic);
++                  // not implemented
++                }
++#else
++                TIME_NOW(&now);
++                if (isc_time_compare (&now, &prev) < 0)
++                  return ISC_R_TIMESHIFTED;
++                TIME_NOW(&prev);
++#endif                
+ 		/*
+ 		 * Check the reload (or suspend) case first for exiting the
+ 		 * loop as fast as possible in case:
+@@ -475,9 +511,8 @@ evloop(isc__appctx_t *ctx) {
+ 			if (result != ISC_R_SUCCESS)
+ 				tvp = NULL;
+ 			else {
+-				uint64_t us;
+-
+ 				TIME_NOW(&now);
++
+ 				us = isc_time_microdiff(&when, &now);
+ 				if (us == 0)
+ 					call_timer_dispatch = true;
+diff --git a/bind/bind-9.11.36/lib/isc/unix/include/isc/time.h b/bind/bind-9.11.36/lib/isc/unix/include/isc/time.h
+index 03512c1..99e0dfa 100644
+--- a/bind/bind-9.11.36/lib/isc/unix/include/isc/time.h
++++ b/bind/bind-9.11.36/lib/isc/unix/include/isc/time.h
+@@ -132,6 +132,26 @@ isc_time_isepoch(const isc_time_t *t);
+  *\li	't' is a valid pointer.
+  */
+ 
++#ifdef CLOCK_BOOTTIME
++isc_result_t
++isc_time_boottime(isc_time_t *t);
++/*%<
++ * Set 't' to monotonic time from previous boot
++ * it's not affected by system time change. It also
++ * includes the time system was suspended
++ *
++ * Requires:
++ *\li	't' is a valid pointer.
++ *
++ * Returns:
++ *
++ *\li	Success
++ *\li	Unexpected error
++ *		Getting the time from the system failed.
++ */
++#endif /* CLOCK_BOOTTIME */
++ 
++
+ isc_result_t
+ isc_time_now(isc_time_t *t);
+ /*%<
+diff --git a/bind/bind-9.11.36/lib/isc/unix/time.c b/bind/bind-9.11.36/lib/isc/unix/time.c
+index bcca41b..af6ea7f 100644
+--- a/bind/bind-9.11.36/lib/isc/unix/time.c
++++ b/bind/bind-9.11.36/lib/isc/unix/time.c
+@@ -498,3 +498,25 @@ isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
+ 			 t->nanoseconds / NS_PER_MS);
+ 	}
+ }
++
++
++#ifdef CLOCK_BOOTTIME
++isc_result_t
++isc_time_boottime(isc_time_t *t) {
++  struct timespec ts;
++  
++  char strbuf[ISC_STRERRORSIZE];
++
++  if (clock_gettime (CLOCK_BOOTTIME, &ts) != 0){
++    isc__strerror(errno, strbuf, sizeof(strbuf));
++    UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
++    return (ISC_R_UNEXPECTED);    
++  }
++
++  t->seconds = ts.tv_sec;
++  t->nanoseconds = ts.tv_nsec;
++
++  return (ISC_R_SUCCESS);
++  
++};
++#endif
+-- 
+2.35.1
+
diff --git a/bind-system-getaddrinfo.patch b/bind-system-getaddrinfo.patch
new file mode 100644
index 0000000..b86936e
--- /dev/null
+++ b/bind-system-getaddrinfo.patch
@@ -0,0 +1,117 @@
+From 9970114f558927564d9c19be969c3c35db3b0edf Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Tue, 22 Jun 2021 06:58:40 +0200
+Subject: [PATCH 28/28] Use system getaddrinfo for dhcp
+
+---
+ .../lib/irs/include/irs/netdb.h.in            | 94 +++++++++++++++++++
+ 1 file changed, 94 insertions(+)
+
+diff --git a/bind/bind-9.11.36/lib/irs/include/irs/netdb.h.in b/bind/bind-9.11.36/lib/irs/include/irs/netdb.h.in
+index 427fef8..74069b5 100644
+--- a/bind/bind-9.11.36/lib/irs/include/irs/netdb.h.in
++++ b/bind/bind-9.11.36/lib/irs/include/irs/netdb.h.in
+@@ -150,6 +150,100 @@ struct addrinfo {
+ #define	NI_NUMERICSERV	0x00000008
+ #define	NI_DGRAM	0x00000010
+ 
++/*
++ * Define to map into irs_ namespace.
++ */
++
++#define IRS_NAMESPACE
++
++#ifdef IRS_NAMESPACE
++
++/*
++ * Use our versions not the ones from the C library.
++ */
++
++#ifdef getnameinfo
++#undef getnameinfo
++#endif
++#define getnameinfo irs_getnameinfo
++
++#ifdef getaddrinfo
++#undef getaddrinfo
++#endif
++#define getaddrinfo irs_getaddrinfo
++
++#ifdef freeaddrinfo
++#undef freeaddrinfo
++#endif
++#define freeaddrinfo irs_freeaddrinfo
++
++#ifdef gai_strerror
++#undef gai_strerror
++#endif
++#define gai_strerror irs_gai_strerror
++
++#endif
++
++extern int getaddrinfo (const char *name,
++			const char *service,
++			const struct addrinfo *req,
++			struct addrinfo **pai);
++extern int getnameinfo (const struct sockaddr *sa,
++			socklen_t salen, char *host,
++			socklen_t hostlen, char *serv,
++			socklen_t servlen, int flags);
++extern void freeaddrinfo (struct addrinfo *ai);
++extern const char *gai_strerror (int ecode);
++
++/*
++ * Define to map into irs_ namespace.
++ */
++
++#define IRS_NAMESPACE
++
++#ifdef IRS_NAMESPACE
++
++/*
++ * Use our versions not the ones from the C library.
++ */
++
++#ifdef getnameinfo
++#undef getnameinfo
++#endif
++#define getnameinfo irs_getnameinfo
++
++#ifdef getaddrinfo
++#undef getaddrinfo
++#endif
++#define getaddrinfo irs_getaddrinfo
++
++#ifdef freeaddrinfo
++#undef freeaddrinfo
++#endif
++#define freeaddrinfo irs_freeaddrinfo
++
++#ifdef gai_strerror
++#undef gai_strerror
++#endif
++#define gai_strerror irs_gai_strerror
++
++int
++getaddrinfo(const char *hostname, const char *servname,
++	    const struct addrinfo *hints, struct addrinfo **res);
++
++int
++getnameinfo(const struct sockaddr *sa, IRS_GETNAMEINFO_SOCKLEN_T salen,
++	    char *host, IRS_GETNAMEINFO_BUFLEN_T hostlen,
++	    char *serv, IRS_GETNAMEINFO_BUFLEN_T servlen,
++	    IRS_GETNAMEINFO_FLAGS_T flags);
++
++void freeaddrinfo (struct addrinfo *ai);
++
++IRS_GAISTRERROR_RETURN_T
++gai_strerror(int ecode);
++
++#endif
++
+ /*
+  * Tell Emacs to use C mode on this file.
+  * Local variables:
+-- 
+2.35.1
+
diff --git a/dhcp-CLOEXEC.patch b/dhcp-CLOEXEC.patch
new file mode 100644
index 0000000..46ac860
--- /dev/null
+++ b/dhcp-CLOEXEC.patch
@@ -0,0 +1,366 @@
+From 39ce1ca26128f4a5d018a567157320ba1f68f4ea Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:27:18 +0100
+Subject: [PATCH 08/28] Make sure all open file descriptors are closed-on-exec
+ for SELinux
+
+ISC-bug: #19148
+---
+ client/clparse.c  |  4 ++--
+ client/dhclient.c | 28 ++++++++++++++--------------
+ common/bpf.c      |  2 +-
+ common/dlpi.c     |  2 +-
+ common/nit.c      |  2 +-
+ common/resolv.c   |  2 +-
+ common/upf.c      |  2 +-
+ omapip/trace.c    |  6 +++---
+ relay/dhcrelay.c  | 10 +++++-----
+ server/confpars.c |  2 +-
+ server/db.c       |  4 ++--
+ server/dhcpd.c    | 14 +++++++-------
+ server/ldap.c     |  2 +-
+ 13 files changed, 40 insertions(+), 40 deletions(-)
+
+diff --git a/client/clparse.c b/client/clparse.c
+index e63ea08..902b523 100644
+--- a/client/clparse.c
++++ b/client/clparse.c
+@@ -291,7 +291,7 @@ int read_client_conf_file (const char *name, struct interface_info *ip,
+ 	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;
+@@ -367,7 +367,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 --git a/client/dhclient.c b/client/dhclient.c
+index 07679a7..aefc119 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
+@@ -279,11 +279,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)
+@@ -771,7 +771,7 @@ main(int argc, char **argv) {
+ 		long temp;
+ 		int e;
+ 
+-		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;
+ 
+@@ -826,7 +826,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;
+ 
+@@ -851,7 +851,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);
+@@ -4054,7 +4054,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;
+@@ -4249,7 +4249,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;
+@@ -4453,7 +4453,7 @@ int write_client_lease (client, lease, rewrite, makesure)
+ 		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;
+@@ -5039,9 +5039,9 @@ void detach ()
+ 	(void) close(2);
+ 
+ 	/* Reopen them on /dev/null. */
+-	(void) open("/dev/null", O_RDWR);
+-	(void) open("/dev/null", O_RDWR);
+-	(void) open("/dev/null", O_RDWR);
++	(void) open("/dev/null", O_RDWR | O_CLOEXEC);
++	(void) open("/dev/null", O_RDWR | O_CLOEXEC);
++	(void) open("/dev/null", O_RDWR | O_CLOEXEC);
+ 
+ 	write_client_pid_file ();
+ 
+@@ -5059,14 +5059,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 --git a/common/bpf.c b/common/bpf.c
+index 0bffcbf..d2a0549 100644
+--- a/common/bpf.c
++++ b/common/bpf.c
+@@ -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 --git a/common/dlpi.c b/common/dlpi.c
+index f2332c0..bf6e21f 100644
+--- a/common/dlpi.c
++++ b/common/dlpi.c
+@@ -817,7 +817,7 @@ dlpiopen(const char *ifname) {
+ 	}
+ 	*dp = '\0';
+ 
+-	return open (devname, O_RDWR, 0);
++	return open (devname, O_RDWR | O_CLOEXEC, 0);
+ }
+ 
+ /*
+diff --git a/common/nit.c b/common/nit.c
+index ba62488..4ebfa4a 100644
+--- a/common/nit.c
++++ b/common/nit.c
+@@ -75,7 +75,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 --git a/common/resolv.c b/common/resolv.c
+index 5fd683f..3535f3e 100644
+--- a/common/resolv.c
++++ b/common/resolv.c
+@@ -43,7 +43,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 --git a/common/upf.c b/common/upf.c
+index 37e5cb2..b7c0649 100644
+--- a/common/upf.c
++++ b/common/upf.c
+@@ -71,7 +71,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 --git a/omapip/trace.c b/omapip/trace.c
+index dc9185f..a605d18 100644
+--- a/omapip/trace.c
++++ b/omapip/trace.c
+@@ -136,10 +136,10 @@ isc_result_t trace_begin (const char *filename,
+ 		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);
+ 	}
+ 
+@@ -427,7 +427,7 @@ void trace_file_replay (const char *filename)
+ 	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 --git a/relay/dhcrelay.c b/relay/dhcrelay.c
+index 946ef1b..a7b1286 100644
+--- a/relay/dhcrelay.c
++++ b/relay/dhcrelay.c
+@@ -305,11 +305,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)
+@@ -800,13 +800,13 @@ main(int argc, char **argv) {
+ 		/* Create the pid file. */
+ 		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 --git a/server/confpars.c b/server/confpars.c
+index 103af1e..5a6396b 100644
+--- a/server/confpars.c
++++ b/server/confpars.c
+@@ -118,7 +118,7 @@ isc_result_t read_conf_file (const char *filename, struct group *group,
+ 	}
+ #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 --git a/server/db.c b/server/db.c
+index cecbf6b..4243a92 100644
+--- a/server/db.c
++++ b/server/db.c
+@@ -1154,7 +1154,7 @@ int new_lease_file (int test_mode)
+ 		     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;
+@@ -1175,7 +1175,7 @@ int new_lease_file (int test_mode)
+ 	}
+ #endif /* PARANOIA */
+ 
+-	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 --git a/server/dhcpd.c b/server/dhcpd.c
+index 3522889..845d0cc 100644
+--- a/server/dhcpd.c
++++ b/server/dhcpd.c
+@@ -300,11 +300,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)
+@@ -975,7 +975,7 @@ main(int argc, char **argv) {
+ 	 * appropriate.
+ 	 */
+ 	if (no_pid_file == ISC_FALSE) {
+-		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)));
+@@ -1028,9 +1028,9 @@ main(int argc, char **argv) {
+                 (void) close(2);
+ 
+                 /* Reopen them on /dev/null. */
+-                (void) open("/dev/null", O_RDWR);
+-                (void) open("/dev/null", O_RDWR);
+-                (void) open("/dev/null", O_RDWR);
++                (void) open("/dev/null", O_RDWR | O_CLOEXEC);
++                (void) open("/dev/null", O_RDWR | O_CLOEXEC);
++                (void) open("/dev/null", O_RDWR | O_CLOEXEC);
+                 log_perror = 0; /* No sense logging to /dev/null. */
+ 
+        		IGNORE_RET (chdir("/"));
+diff --git a/server/ldap.c b/server/ldap.c
+index e3e48f4..1a68936 100644
+--- a/server/ldap.c
++++ b/server/ldap.c
+@@ -1447,7 +1447,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));
+-- 
+2.35.1
+
diff --git a/dhcp-add-guid-duid-to-logs.patch b/dhcp-add-guid-duid-to-logs.patch
new file mode 100644
index 0000000..d5596b8
--- /dev/null
+++ b/dhcp-add-guid-duid-to-logs.patch
@@ -0,0 +1,327 @@
+From 3baf35269555e2223dbd1733cb1c475cb7f2ed7a Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:35:47 +0100
+Subject: [PATCH 15/28] Add GUID/DUID to dhcpd logs (#1064416)
+
+---
+ client/dhclient.c | 70 ++++++++++++++++++++++++++++++++++--------
+ server/dhcp.c     | 78 ++++++++++++++++++++++++++++-------------------
+ 2 files changed, 105 insertions(+), 43 deletions(-)
+
+diff --git a/client/dhclient.c b/client/dhclient.c
+index 48edddf..181f6e1 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
+@@ -1176,6 +1176,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
+@@ -1204,14 +1224,34 @@ main(int argc, char **argv) {
+ 		   Not much entropy, but we're booting, so we're not likely to
+ 		   find anything better. */
+ 
++		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;
+ 		}
+-		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 */
++		}
++		seed += ((unsigned)(cur_tv.tv_usec * 1000000)) + (unsigned)getpid();
+ 	}
+ 	srandom(seed);
+ 
+@@ -1869,9 +1909,10 @@ void dhcpack (packet)
+ 		return;
+ 	}
+ 
+-	log_info ("DHCPACK of %s from %s",
++	log_info ("DHCPACK of %s from %s (xid=0x%x)",
+ 		  inet_ntoa(packet->raw->yiaddr),
+-		  piaddr (packet->client_addr));
++		  piaddr (packet -> client_addr),
++		  ntohl(client -> xid));
+ 
+ 	/* Check v6only first. */
+ 	v6only_wait = check_v6only(packet, client);
+@@ -2825,7 +2866,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), ntohl(client -> xid));
+ 
+ 	if (!client -> active) {
+ #if defined (DEBUG)
+@@ -2958,10 +2999,10 @@ void send_discover (cpp)
+ 			  (long)(client -> interval));
+ 	} else
+ #endif
+-	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), ntohl(client -> xid));
+ 
+ 	/* Send out a packet. */
+ #if defined(DHCPv6) && defined(DHCP4o6)
+@@ -3355,10 +3396,12 @@ void send_request (cpp)
+ 	}
+ 
+ 	strncpy(rip_buf, rip_str, sizeof(rip_buf)-1);
+-	log_info ("DHCPREQUEST for %s on %s to %s port %d", rip_buf,
++	log_info ("DHCPREQUEST for %s on %s to %s port %d (xid=0x%x)",
++                  rip_buf,
+ 		  client->name ? client->name : client->interface->name,
+ 		  inet_ntoa(destination.sin_addr),
+-		  ntohs (destination.sin_port));
++		  ntohs (destination.sin_port),
++                  ntohl(client -> xid));
+ 
+ #if defined(DHCPv6) && defined(DHCP4o6)
+ 	if (dhcpv4_over_dhcpv6) {
+@@ -3415,11 +3458,13 @@ void send_decline (cpp)
+ 		log_info ("DHCPDECLINE");
+ 	} else
+ #endif
+-	log_info ("DHCPDECLINE of %s on %s to %s port %d",
++	log_info ("DHCPDECLINE of %s on %s to %s port %d (xid=0x%x)",                  
+ 		  piaddr(client->requested_address),
+ 		  (client->name ? client->name : client->interface->name),
+ 		  inet_ntoa(sockaddr_broadcast.sin_addr),
+-		  ntohs(sockaddr_broadcast.sin_port));
++		  ntohs(sockaddr_broadcast.sin_port),
++                  ntohl(client -> xid));
++
+ 
+ 	/* Send out a packet. */
+ #if defined(DHCPv6) && defined(DHCP4o6)
+@@ -3478,11 +3523,12 @@ void send_release (cpp)
+ 		log_info ("DHCPRELEASE");
+ 	} else
+ #endif
+-	log_info ("DHCPRELEASE of %s on %s to %s port %d",
++	log_info ("DHCPRELEASE of %s on %s to %s port %d (xid=0x%x)",
+ 		  piaddr(client->active->address),
+ 		  client->name ? client->name : client->interface->name,
+ 		  inet_ntoa (destination.sin_addr),
+-		  ntohs (destination.sin_port));
++		  ntohs (destination.sin_port),
++                  ntohl(client -> xid));
+ 
+ #if defined(DHCPv6) && defined(DHCP4o6)
+ 	if (dhcpv4_over_dhcpv6) {
+diff --git a/server/dhcp.c b/server/dhcp.c
+index ae805a6..8363840 100644
+--- a/server/dhcp.c
++++ b/server/dhcp.c
+@@ -93,6 +93,42 @@ const int dhcp_type_name_max = ((sizeof dhcp_type_names) / sizeof (char *));
+ 
+ static TIME leaseTimeCheck(TIME calculated, TIME alternate);
+ 
++char *print_client_identifier_from_packet (packet)
++	struct packet *packet;
++{
++	struct option_cache *oc;
++	struct data_string client_identifier;
++	char *ci;
++
++	memset (&client_identifier, 0, sizeof client_identifier);
++
++	oc = lookup_option (&dhcp_universe, packet -> options,
++			DHO_DHCP_CLIENT_IDENTIFIER);
++	if (oc &&
++	    evaluate_option_cache (&client_identifier,
++				    packet, (struct lease *)0,
++				    (struct client_state *)0,
++				    packet -> options,
++				    (struct option_state *)0,
++				    &global_scope, oc, MDL)) {
++		ci = print_hw_addr (HTYPE_INFINIBAND, client_identifier.len, client_identifier.data);
++		data_string_forget (&client_identifier, MDL);
++		return ci;
++	} else
++		return "\"no client id\"";
++}
++
++char *print_hw_addr_or_client_id (packet)
++	struct packet *packet;
++{
++	if (packet -> raw -> htype == HTYPE_INFINIBAND)
++		return print_client_identifier_from_packet (packet);
++	else
++		return print_hw_addr (packet -> raw -> htype,
++				      packet -> raw -> hlen,
++				      packet -> raw -> chaddr);
++}
++
+ void
+ dhcp (struct packet *packet) {
+ 	int ms_nulltp = 0;
+@@ -135,9 +171,7 @@ dhcp (struct packet *packet) {
+ 
+ 		log_info("%s from %s via %s: %s", s,
+ 			 (packet->raw->htype
+-			  ? print_hw_addr(packet->raw->htype,
+-					  packet->raw->hlen,
+-					  packet->raw->chaddr)
++			  ? print_hw_addr_or_client_id(packet)
+ 			  : "<no identifier>"),
+ 			 packet->raw->giaddr.s_addr
+ 			 ? inet_ntoa(packet->raw->giaddr)
+@@ -334,9 +368,7 @@ void dhcpdiscover (packet, ms_nulltp)
+ #endif
+ 	snprintf (msgbuf, sizeof msgbuf, "DHCPDISCOVER from %s %s%s%svia %s",
+ 		 (packet -> raw -> htype
+-		  ? print_hw_addr (packet -> raw -> htype,
+-				   packet -> raw -> hlen,
+-				   packet -> raw -> chaddr)
++		  ? print_hw_addr_or_client_id (packet)
+ 		  : (lease
+ 		     ? print_hex_1(lease->uid_len, lease->uid, 60)
+ 		     : "<no identifier>")),
+@@ -548,9 +580,7 @@ void dhcprequest (packet, ms_nulltp, ip_lease)
+ 		 "DHCPREQUEST for %s%s from %s %s%s%svia %s",
+ 		 piaddr (cip), smbuf,
+ 		 (packet -> raw -> htype
+-		  ? print_hw_addr (packet -> raw -> htype,
+-				   packet -> raw -> hlen,
+-				   packet -> raw -> chaddr)
++		  ? print_hw_addr_or_client_id(packet)
+ 		  : (lease
+ 		     ? print_hex_1(lease->uid_len, lease->uid, 60)
+ 		     : "<no identifier>")),
+@@ -791,9 +821,7 @@ void dhcprelease (packet, ms_nulltp)
+ 	if ((oc = lookup_option (&dhcp_universe, packet -> options,
+ 				 DHO_DHCP_REQUESTED_ADDRESS))) {
+ 		log_info ("DHCPRELEASE from %s specified requested-address.",
+-		      print_hw_addr (packet -> raw -> htype,
+-				     packet -> raw -> hlen,
+-				     packet -> raw -> chaddr));
++		      print_hw_addr_or_client_id(packet));
+ 	}
+ 
+ 	oc = lookup_option (&dhcp_universe, packet -> options,
+@@ -885,9 +913,7 @@ void dhcprelease (packet, ms_nulltp)
+ 		 "DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)",
+ 		 cstr,
+ 		 (packet -> raw -> htype
+-		  ? print_hw_addr (packet -> raw -> htype,
+-				   packet -> raw -> hlen,
+-				   packet -> raw -> chaddr)
++		  ? print_hw_addr_or_client_id(packet)
+ 		  : (lease
+ 		     ? print_hex_1(lease->uid_len, lease->uid, 60)
+ 		     : "<no identifier>")),
+@@ -992,9 +1018,7 @@ void dhcpdecline (packet, ms_nulltp)
+ 		 "DHCPDECLINE of %s from %s %s%s%svia %s",
+ 		 piaddr (cip),
+ 		 (packet -> raw -> htype
+-		  ? print_hw_addr (packet -> raw -> htype,
+-				   packet -> raw -> hlen,
+-				   packet -> raw -> chaddr)
++		  ? print_hw_addr_or_client_id(packet)
+ 		  : (lease
+ 		     ? print_hex_1(lease->uid_len, lease->uid, 60)
+ 		     : "<no identifier>")),
+@@ -1740,8 +1764,7 @@ void dhcpinform (packet, ms_nulltp)
+ 	/* Report what we're sending. */
+ 	snprintf(msgbuf, sizeof msgbuf, "DHCPACK to %s (%s) via", piaddr(cip),
+ 		 (packet->raw->htype && packet->raw->hlen) ?
+-			print_hw_addr(packet->raw->htype, packet->raw->hlen,
+-				      packet->raw->chaddr) :
++			print_hw_addr_or_client_id(packet) :
+ 			"<no client hardware address>");
+ 	log_info("%s %s", msgbuf, gip.len ? piaddr(gip) :
+ 					    packet->interface->name);
+@@ -1926,9 +1949,7 @@ void nak_lease (packet, cip, network_group)
+ #endif
+ 	log_info ("DHCPNAK on %s to %s via %s",
+ 	      piaddr (*cip),
+-	      print_hw_addr (packet -> raw -> htype,
+-			     packet -> raw -> hlen,
+-			     packet -> raw -> chaddr),
++	      print_hw_addr_or_client_id(packet),
+ 	      packet -> raw -> giaddr.s_addr
+ 	      ? inet_ntoa (packet -> raw -> giaddr)
+ 	      : packet -> interface -> name);
+@@ -4044,7 +4065,7 @@ void dhcp_reply (lease)
+ 		   ? (state -> offer == DHCPACK ? "DHCPACK" : "DHCPOFFER")
+ 		   : "BOOTREPLY"),
+ 		  piaddr (lease -> ip_addr),
+-		  (lease -> hardware_addr.hlen
++		  (lease -> hardware_addr.hlen > 1
+ 		   ? print_hw_addr (lease -> hardware_addr.hbuf [0],
+ 				    lease -> hardware_addr.hlen - 1,
+ 				    &lease -> hardware_addr.hbuf [1])
+@@ -4605,10 +4626,7 @@ int find_lease (struct lease **lp,
+ 			if (uid_lease) {
+ 			    if (uid_lease->binding_state == FTS_ACTIVE) {
+ 				log_error ("client %s has duplicate%s on %s",
+-					   (print_hw_addr
+-					    (packet -> raw -> htype,
+-					     packet -> raw -> hlen,
+-					     packet -> raw -> chaddr)),
++					   (print_hw_addr_or_client_id(packet)),
+ 					   " leases",
+ 					   (ip_lease -> subnet ->
+ 					    shared_network -> name));
+@@ -4775,9 +4793,7 @@ int find_lease (struct lease **lp,
+ 			log_error("uid lease %s for client %s is duplicate "
+ 				  "on %s",
+ 				  piaddr(uid_lease->ip_addr),
+-				  print_hw_addr(packet->raw->htype,
+-						packet->raw->hlen,
+-						packet->raw->chaddr),
++				  print_hw_addr_or_client_id(packet),
+ 				  uid_lease->subnet->shared_network->name);
+ 
+ 			if (!packet -> raw -> ciaddr.s_addr &&
+-- 
+2.35.1
+
diff --git a/dhcp-capabilities.patch b/dhcp-capabilities.patch
new file mode 100644
index 0000000..3ac1973
--- /dev/null
+++ b/dhcp-capabilities.patch
@@ -0,0 +1,266 @@
+From 7ea2433d716172f160c9380ed0bb852fafe845a2 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:30:28 +0100
+Subject: [PATCH 11/28] Drop unnecessary capabilities
+
+dhclient (#517649, #546765), dhcpd/dhcrelay (#699713)
+---
+ client/Makefile.am       |  3 ++-
+ client/dhclient-script.8 | 10 ++++++++++
+ client/dhclient.8        | 29 +++++++++++++++++++++++++++++
+ client/dhclient.c        | 24 ++++++++++++++++++++++++
+ configure.ac             | 35 +++++++++++++++++++++++++++++++++++
+ relay/Makefile.am        |  3 ++-
+ relay/dhcrelay.c         | 29 +++++++++++++++++++++++++++++
+ 7 files changed, 131 insertions(+), 2 deletions(-)
+
+diff -urNp -x '*.orig' dhcp-4.4.3.org/client/Makefile.am dhcp-4.4.3/client/Makefile.am
+--- dhcp-4.4.3.org/client/Makefile.am	2022-03-08 09:26:03.000000000 +0000
++++ dhcp-4.4.3/client/Makefile.am	2022-04-03 17:02:38.643517435 +0000
+@@ -17,6 +17,7 @@ dhclient_LDADD = ../common/libdhcp. at A@ .
+ 		 @BINDLIBIRSDIR@/libirs. at A@ \
+ 		 @BINDLIBDNSDIR@/libdns. at A@ \
+ 		 @BINDLIBISCCFGDIR@/libisccfg. at A@ \
+-		 @BINDLIBISCDIR@/libisc. at A@
++		 @BINDLIBISCDIR@/libisc. at A@ \
++		 $(CAPNG_LDADD)
+ man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
+ EXTRA_DIST = $(man_MANS)
+diff -urNp -x '*.orig' dhcp-4.4.3.org/client/dhclient-script.8 dhcp-4.4.3/client/dhclient-script.8
+--- dhcp-4.4.3.org/client/dhclient-script.8	2022-04-03 17:02:38.454517007 +0000
++++ dhcp-4.4.3/client/dhclient-script.8	2022-04-03 17:02:38.643517435 +0000
+@@ -249,6 +249,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 -urNp -x '*.orig' dhcp-4.4.3.org/client/dhclient.8 dhcp-4.4.3/client/dhclient.8
+--- dhcp-4.4.3.org/client/dhclient.8	2022-04-03 17:02:38.455517009 +0000
++++ dhcp-4.4.3/client/dhclient.8	2022-04-03 17:02:38.643517435 +0000
+@@ -135,6 +135,9 @@ dhclient - Dynamic Host Configuration Pr
+ .B -w
+ ]
+ [
++.B -nc
++]
++[
+ .B -B
+ ]
+ [
+@@ -330,6 +333,32 @@ program can then be used to notify the c
+ has been added or removed, so that the client can attempt to configure an IP
+ 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 \-n
+ Do not configure any interfaces.  This is most likely to be useful in
+ combination with the
+diff -urNp -x '*.orig' dhcp-4.4.3.org/client/dhclient.c dhcp-4.4.3/client/dhclient.c
+--- dhcp-4.4.3.org/client/dhclient.c	2022-04-03 17:02:38.461517023 +0000
++++ dhcp-4.4.3/client/dhclient.c	2022-04-03 17:02:38.644517437 +0000
+@@ -41,6 +41,10 @@
+ #include <sys/wait.h>
+ #include <limits.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.
+@@ -269,6 +273,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));
+@@ -668,6 +675,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("Unknown command: %s", argv[i]);
+ 		} else if (interfaces_requested < 0) {
+@@ -728,6 +739,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 -urNp -x '*.orig' dhcp-4.4.3.org/configure.ac dhcp-4.4.3/configure.ac
+--- dhcp-4.4.3.org/configure.ac	2022-04-03 17:02:38.459517018 +0000
++++ dhcp-4.4.3/configure.ac	2022-04-03 17:02:38.644517437 +0000
+@@ -603,6 +603,41 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],
+ # 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 -urNp -x '*.orig' dhcp-4.4.3.org/relay/Makefile.am dhcp-4.4.3/relay/Makefile.am
+--- dhcp-4.4.3.org/relay/Makefile.am	2022-03-08 09:26:03.000000000 +0000
++++ dhcp-4.4.3/relay/Makefile.am	2022-04-03 17:02:38.644517437 +0000
+@@ -8,6 +8,7 @@ dhcrelay_LDADD = ../common/libdhcp. at A@ .
+ 		 @BINDLIBIRSDIR@/libirs. at A@ \
+ 		 @BINDLIBDNSDIR@/libdns. at A@ \
+ 		 @BINDLIBISCCFGDIR@/libisccfg. at A@ \
+-		 @BINDLIBISCDIR@/libisc. at A@
++		 @BINDLIBISCDIR@/libisc. at A@ \
++		 $(CAPNG_LDADD)
+ man_MANS = dhcrelay.8
+ EXTRA_DIST = $(man_MANS)
+diff -urNp -x '*.orig' dhcp-4.4.3.org/relay/dhcrelay.c dhcp-4.4.3/relay/dhcrelay.c
+--- dhcp-4.4.3.org/relay/dhcrelay.c	2022-04-03 17:02:38.462517025 +0000
++++ dhcp-4.4.3/relay/dhcrelay.c	2022-04-03 17:02:38.645517439 +0000
+@@ -36,6 +36,11 @@
+ #include <systemd/sd-daemon.h>
+ #endif
+ 
++#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];
+@@ -616,6 +621,10 @@ main(int argc, char **argv) {
+ 				usage(use_noarg, argv[i-1]);
+ 			dhcrelay_sub_id = argv[i];
+ #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(use_noarg, argv[i-1]);
+@@ -685,6 +694,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);
+@@ -849,6 +869,15 @@ main(int argc, char **argv) {
+                    (unsigned long) getpid());
+ #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 --git a/dhcp-client-request-release-bind-iface.patch b/dhcp-client-request-release-bind-iface.patch
new file mode 100644
index 0000000..37482a0
--- /dev/null
+++ b/dhcp-client-request-release-bind-iface.patch
@@ -0,0 +1,76 @@
+From d45463c2007a78623f2c90c250bb8e2f3e34a852 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:39:36 +0100
+Subject: [PATCH 17/28] Send unicast request/release via correct interface
+
+(#800561, #1177351)
+(Submitted to dhcp-bugs at isc.org - [ISC-Bugs #30544])
+---
+ client/dhclient.c | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/client/dhclient.c b/client/dhclient.c
+index 444d251..d607975 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
+@@ -3417,6 +3417,14 @@ void send_request (cpp)
+ #endif
+ 	if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
+ 	    fallback_interface) {
++#if defined(SO_BINDTODEVICE)
++		if (setsockopt(fallback_interface -> wfdesc, SOL_SOCKET,
++			       SO_BINDTODEVICE, client->interface->name,
++			       strlen(client->interface->name)) < 0) {
++			log_error("%s:%d: Failed to bind fallback interface"
++				  " to %s: %m", MDL, client->interface->name);
++		}
++#endif
+ 		result = send_packet(fallback_interface, NULL, &client->packet,
+ 				     client->packet_length, from, &destination,
+ 				     NULL);
+@@ -3426,6 +3434,13 @@ void send_request (cpp)
+ 				  client->packet_length,
+ 				  fallback_interface->name);
+ 		}
++#if defined(SO_BINDTODEVICE)
++		if (setsockopt(fallback_interface -> wfdesc, SOL_SOCKET,
++			       SO_BINDTODEVICE, NULL, 0) < 0) {
++			log_fatal("%s:%d: Failed to unbind fallback interface:"
++				  " %m", MDL);
++		}
++#endif
+         }
+ 	else {
+ 		/* Send out a packet. */
+@@ -3543,6 +3558,14 @@ void send_release (cpp)
+ 	} else
+ #endif
+ 	if (fallback_interface) {
++#if defined(SO_BINDTODEVICE)
++		if (setsockopt(fallback_interface -> wfdesc, SOL_SOCKET,
++			       SO_BINDTODEVICE, client->interface->name,
++			       strlen(client->interface->name)) < 0) {
++			log_error("%s:%d: Failed to bind fallback interface"
++				  " to %s: %m", MDL, client->interface->name);
++		}
++#endif
+ 		result = send_packet(fallback_interface, NULL, &client->packet,
+ 				      client->packet_length, from, &destination,
+ 				      NULL);
+@@ -3552,6 +3575,13 @@ void send_release (cpp)
+ 				  client->packet_length,
+ 				  fallback_interface->name);
+ 		}
++#if defined(SO_BINDTODEVICE)
++		if (setsockopt(fallback_interface -> wfdesc, SOL_SOCKET,
++			       SO_BINDTODEVICE, NULL, 0) < 0) {
++			log_fatal("%s:%d: Failed to unbind fallback interface:"
++				  " %m", MDL);
++		}
++#endif
+         } else {
+ 		/* Send out a packet. */
+ 		result = send_packet(client->interface, NULL, &client->packet,
+-- 
+2.35.1
+
diff --git a/dhcp-confparse.patch b/dhcp-confparse.patch
new file mode 100644
index 0000000..25824fd
--- /dev/null
+++ b/dhcp-confparse.patch
@@ -0,0 +1,56 @@
+From bdbbb4be07bb33fe083baef2bd0ef38b91c11120 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:44:06 +0100
+Subject: [PATCH 21/28] Load leases DB in non-replay mode only
+
+---
+ server/confpars.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/server/confpars.c b/server/confpars.c
+index 5a6396b..6e08ad7 100644
+--- a/server/confpars.c
++++ b/server/confpars.c
+@@ -134,6 +134,11 @@ isc_result_t read_conf_file (const char *filename, struct group *group,
+ 
+ 	cfile = (struct parse *)0;
+ #if defined (TRACING)
++	// No need to dmalloc huge memory region if we're not going to re-play
++	if (!trace_record()){
++		status = new_parse(&cfile, file, NULL, 0, filename, 0);
++		goto noreplay;
++	};
+ 	flen = lseek (file, (off_t)0, SEEK_END);
+ 	if (flen < 0) {
+ 	      boom:
+@@ -165,7 +170,6 @@ isc_result_t read_conf_file (const char *filename, struct group *group,
+ 	if (result != ulen)
+ 		log_fatal ("%s: short read of %d bytes instead of %d.",
+ 			   filename, ulen, result);
+-	close (file);
+       memfile:
+ 	/* If we're recording, write out the filename and file contents. */
+ 	if (trace_record ())
+@@ -174,6 +178,9 @@ isc_result_t read_conf_file (const char *filename, struct group *group,
+ #else
+ 	status = new_parse(&cfile, file, NULL, 0, filename, 0);
+ #endif
++      noreplay:
++	if (!trace_playback())
++		close (file);
+ 	if (status != ISC_R_SUCCESS || cfile == NULL)
+ 		return status;
+ 
+@@ -183,7 +190,8 @@ isc_result_t read_conf_file (const char *filename, struct group *group,
+ 		status = conf_file_subparse (cfile, group, group_type);
+ 	end_parse (&cfile);
+ #if defined (TRACING)
+-	dfree (dbuf, MDL);
++	if (trace_record())
++	    dfree (dbuf, MDL);
+ #endif
+ 	return status;
+ }
+-- 
+2.35.1
+
diff --git a/dhcp-default-requested-options.patch b/dhcp-default-requested-options.patch
index f57fa1f..98c1957 100644
--- a/dhcp-default-requested-options.patch
+++ b/dhcp-default-requested-options.patch
@@ -1,6 +1,18 @@
-diff -up dhcp-4.3.4/client/clparse.c.requested dhcp-4.3.4/client/clparse.c
---- dhcp-4.3.4/client/clparse.c.requested	2016-04-29 12:18:50.157151352 +0200
-+++ dhcp-4.3.4/client/clparse.c	2016-04-29 12:19:22.235137243 +0200
+From f994c4d208a8fe88cbf78d4374c8d44793f0598e Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:24:24 +0100
+Subject: [PATCH 05/28] Change default requested options
+
+Add NIS domain, NIS servers, NTP servers, interface-mtu and domain-search
+to the list of default requested DHCP options
+---
+ client/clparse.c | 27 ++++++++++++++++++++++++++-
+ 1 file changed, 26 insertions(+), 1 deletion(-)
+
+diff --git a/client/clparse.c b/client/clparse.c
+index bb63825..e63ea08 100644
+--- a/client/clparse.c
++++ b/client/clparse.c
 @@ -31,7 +31,7 @@
  
  struct client_config top_level_config;
@@ -10,7 +22,7 @@ diff -up dhcp-4.3.4/client/clparse.c.requested dhcp-4.3.4/client/clparse.c
  /* There can be 2 extra requested options for DHCPv4-over-DHCPv6. */
  struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 2 + 1];
  
-@@ -116,6 +116,31 @@ isc_result_t read_client_conf ()
+@@ -119,6 +119,31 @@ isc_result_t read_client_conf ()
  	option_code_hash_lookup(&default_requested_options[8],
  				dhcpv6_universe.code_hash, &code, 0, MDL);
  
@@ -42,3 +54,6 @@ diff -up dhcp-4.3.4/client/clparse.c.requested dhcp-4.3.4/client/clparse.c
  	for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
  		if (default_requested_options[code] == NULL)
  			log_fatal("Unable to find option definition for "
+-- 
+2.35.1
+
diff --git a/dhcp-detect-time-changes.patch b/dhcp-detect-time-changes.patch
new file mode 100644
index 0000000..77df3fd
--- /dev/null
+++ b/dhcp-detect-time-changes.patch
@@ -0,0 +1,92 @@
+From a2fb8759ab48c88e3f8df94ae6e156c357d932a2 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Tue, 22 Oct 2019 16:23:01 +0200
+Subject: [PATCH 24/28] Detect system time changes
+
+---
+ client/dhclient.c |  6 ++++++
+ common/dispatch.c | 11 ++++++++++-
+ includes/dhcpd.h  |  3 ++-
+ server/dhcpd.c    |  6 ++++++
+ 4 files changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/client/dhclient.c b/client/dhclient.c
+index 60836b4..fd18813 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
+@@ -5665,6 +5665,12 @@ isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
+ 		  case server_awaken:
+ 		    state_reboot (client);
+ 		    break;
++
++                  case server_time_changed:
++                    if (client->active){
++                      state_reboot (client);
++                    }
++                    break;
+ 		}
+ 	    }
+ 	}
+diff --git a/common/dispatch.c b/common/dispatch.c
+index 9741ff5..11c1787 100644
+--- a/common/dispatch.c
++++ b/common/dispatch.c
+@@ -118,7 +118,6 @@ dispatch(void)
+ 		 * signal. It will return ISC_R_RELOAD in that
+ 		 * case. That is a normal behavior.
+ 		 */
+-
+ 		if (status == ISC_R_RELOAD) {
+ 			/*
+ 			 * dhcp_set_control_state() will do the job.
+@@ -129,6 +128,16 @@ dispatch(void)
+ 			if (status == ISC_R_SUCCESS)
+ 				status = ISC_R_RELOAD;
+ 		}
++
++                
++                if (status == ISC_R_TIMESHIFTED){
++                  status = dhcp_set_control_state(server_time_changed,
++                                                  server_time_changed);
++                  status = ISC_R_RELOAD;
++                  log_info ("System time has been changed. Unable to use existing leases. Restarting");
++                  // do nothing, restart context
++                };
++
+ 	} while (status == ISC_R_RELOAD);
+ 
+ 	log_fatal ("Dispatch routine failed: %s -- exiting",
+diff --git a/includes/dhcpd.h b/includes/dhcpd.h
+index fabad01..9663508 100644
+--- a/includes/dhcpd.h
++++ b/includes/dhcpd.h
+@@ -524,7 +524,8 @@ typedef enum {
+ 	server_running = 1,
+ 	server_shutdown = 2,
+ 	server_hibernate = 3,
+-	server_awaken = 4
++	server_awaken = 4,
++        server_time_changed = 5
+ } control_object_state_t;
+ 
+ typedef struct {
+diff --git a/server/dhcpd.c b/server/dhcpd.c
+index 845d0cc..3b3bd3b 100644
+--- a/server/dhcpd.c
++++ b/server/dhcpd.c
+@@ -1767,6 +1767,12 @@ isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
+ {
+ 	struct timeval tv;
+ 
++        if (newstate == server_time_changed){
++          log_error ("System time has been changed. Leases information unreliable!");
++          return ISC_R_SUCCESS;
++        }
++
++                
+ 	if (newstate != server_shutdown)
+ 		return DHCP_R_INVALIDARG;
+ 	/* Re-entry. */
+-- 
+2.35.1
+
diff --git a/dhcp-duid_uuid.patch b/dhcp-duid_uuid.patch
new file mode 100644
index 0000000..e7f4e7e
--- /dev/null
+++ b/dhcp-duid_uuid.patch
@@ -0,0 +1,125 @@
+From 0a0a7e1afa171289b9e9d855c519101bbd71b5fe Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:36:30 +0100
+Subject: [PATCH 16/28] Turn on creating/sending of DUID
+
+as client identifier with DHCPv4 clients (#560361c#40, rfc4361)
+---
+ client/dhclient.c | 74 ++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 70 insertions(+), 4 deletions(-)
+
+diff --git a/client/dhclient.c b/client/dhclient.c
+index 181f6e1..444d251 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
+@@ -4267,6 +4267,59 @@ write_options(struct client_state *client, struct option_state *options,
+ 	}
+ }
+ 
++int unhexchar(char c) {
++
++	if (c >= '0' && c <= '9')
++		return c - '0';
++
++	if (c >= 'a' && c <= 'f')
++		return c - 'a' + 10;
++
++	if (c >= 'A' && c <= 'F')
++		return c - 'A' + 10;
++
++	return -1;
++}
++
++isc_result_t
++read_uuid(u_int8_t* uuid) {
++	const char *id_fname = "/etc/machine-id";
++	char id[32];
++	size_t nread;
++	FILE * file = fopen( id_fname , "r");
++	if (!file) {
++		log_debug("Cannot open %s", id_fname);
++		return ISC_R_IOERROR;
++	}
++	nread = fread(id, 1, sizeof id, file);
++	fclose(file);
++
++	if (nread < 32) {
++		log_debug("Not enough data in %s", id_fname);
++		return ISC_R_IOERROR;
++	}
++	int j;
++	for (j = 0; j < 16; j++) {
++		int a, b;
++
++		a = unhexchar(id[j*2]);
++		b = unhexchar(id[j*2+1]);
++
++		if (a < 0 || b < 0) {
++			log_debug("Wrong data in %s", id_fname);
++                        return ISC_R_IOERROR;
++		}
++		uuid[j] = a << 4 | b;
++	}
++
++	/* Set UUID version to 4 --- truly random generation */
++	uuid[6] = (uuid[6] & 0x0F) | 0x40;
++	/* Set the UUID variant to DCE */
++	uuid[8] = (uuid[8] & 0x3F) | 0x80;
++
++	return ISC_R_SUCCESS;
++}
++
+ /*
+  * The "best" default DUID, since we cannot predict any information
+  * about the system (such as whether or not the hardware addresses are
+@@ -4287,6 +4340,7 @@ form_duid(struct data_string *duid, const char *file, int line)
+ 	struct interface_info *ip;
+ 	int len;
+ 	char *str;
++	u_int8_t uuid[16];
+ 
+ 	/* For now, just use the first interface on the list. */
+ 	ip = interfaces;
+@@ -4307,9 +4361,16 @@ form_duid(struct data_string *duid, const char *file, int line)
+ 	    (ip->hw_address.hlen > sizeof(ip->hw_address.hbuf)))
+ 		log_fatal("Impossible hardware address length at %s:%d.", MDL);
+ 
+-	if (duid_type == 0)
+-		duid_type = stateless ? DUID_LL : DUID_LLT;
+-
++	if (duid_type == 0) {
++		if (read_uuid(uuid) == ISC_R_SUCCESS)
++		    duid_type = DUID_UUID;
++		else
++		    duid_type = stateless ? DUID_LL : DUID_LLT;
++	}
++	
++	if (duid_type == DUID_UUID)
++		len = 2 + sizeof (uuid);
++	else {
+ 	/*
+ 	 * 2 bytes for the 'duid type' field.
+ 	 * 2 bytes for the 'htype' field.
+@@ -4320,13 +4381,18 @@ form_duid(struct data_string *duid, const char *file, int line)
+ 	len = 4 + (ip->hw_address.hlen - 1);
+ 	if (duid_type == DUID_LLT)
+ 		len += 4;
++	}
+ 	if (!buffer_allocate(&duid->buffer, len, MDL))
+ 		log_fatal("no memory for default DUID!");
+ 	duid->data = duid->buffer->data;
+ 	duid->len = len;
+ 
++	if (duid_type == DUID_UUID) {
++		putUShort(duid->buffer->data, DUID_UUID);
++		memcpy(duid->buffer->data + 2, uuid, sizeof(uuid));
++	}
+ 	/* Basic Link Local Address type of DUID. */
+-	if (duid_type == DUID_LLT) {
++	else if (duid_type == DUID_LLT) {
+ 		putUShort(duid->buffer->data, DUID_LLT);
+ 		putUShort(duid->buffer->data + 2, ip->hw_address.hbuf[0]);
+ 		putULong(duid->buffer->data + 4, cur_time - DUID_TIME_EPOCH);
+-- 
+2.35.1
+
diff --git a/dhcp-errwarn-message.patch b/dhcp-errwarn-message.patch
index c90f0bd..8c8211f 100644
--- a/dhcp-errwarn-message.patch
+++ b/dhcp-errwarn-message.patch
@@ -1,7 +1,17 @@
-diff -up dhcp-4.3.5/omapip/errwarn.c.errwarn dhcp-4.3.5/omapip/errwarn.c
---- dhcp-4.3.5/omapip/errwarn.c.errwarn	2016-09-27 21:16:50.000000000 +0200
-+++ dhcp-4.3.5/omapip/errwarn.c	2016-11-29 19:44:03.515031147 +0100
-@@ -49,6 +49,41 @@ void (*log_cleanup) (void);
+From 5e9162c5ad7aa98f7f673ac7a7f46905ba2deea4 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:09:57 +0100
+Subject: [PATCH 01/28] change bug url
+
+---
+ omapip/errwarn.c | 47 ++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 42 insertions(+), 5 deletions(-)
+
+diff --git a/omapip/errwarn.c b/omapip/errwarn.c
+index 38dd9c5..d88e392 100644
+--- a/omapip/errwarn.c
++++ b/omapip/errwarn.c
+@@ -48,6 +48,41 @@ void (*log_cleanup) (void);
  static char mbuf [CVT_BUF_MAX + 1];
  static char fbuf [CVT_BUF_MAX + 1];
  
@@ -62,3 +72,6 @@ diff -up dhcp-4.3.5/omapip/errwarn.c.errwarn dhcp-4.3.5/omapip/errwarn.c
    log_error ("%s", "");
    log_error ("exiting.");
  
+-- 
+2.35.1
+
diff --git a/dhcp-extravars.patch b/dhcp-extravars.patch
index dbbbe0b..e1461bf 100644
--- a/dhcp-extravars.patch
+++ b/dhcp-extravars.patch
@@ -1,33 +1,37 @@
---- dhcp-4.4.2/client/dhclient.c.extravars	2021-04-02 12:50:00.989139908 +0000
-+++ dhcp-4.4.2/client/dhclient.c		2021-04-02 12:55:15.477409996 +0000
-@@ -89,8 +89,6 @@ static const char message [] = "Internet
+diff -ur dhcp-4.4.3.orig/client/dhclient.c dhcp-4.4.3/client/dhclient.c
+--- dhcp-4.4.3.orig/client/dhclient.c	2022-04-03 16:57:37.339835264 +0000
++++ dhcp-4.4.3/client/dhclient.c	2022-04-03 16:59:11.169047699 +0000
+@@ -89,9 +89,6 @@
  static const char url [] = "For info, please visit https://www.isc.org/software/dhcp/";
  #endif /* UNIT_TEST */
  
--u_int16_t local_port = 0;
--u_int16_t remote_port = 0;
+-extern u_int16_t local_port;
+-extern u_int16_t remote_port;
+-
  #if defined(DHCPv6) && defined(DHCP4o6)
  int dhcp4o6_state = -1; /* -1 = stopped, 0 = polling, 1 = started */
  #endif
---- dhcp-4.4.2/relay/dhcrelay.c.extravars	2021-04-02 13:05:13.513727484 +0000
-+++ dhcp-4.4.2/relay/dhcrelay.c			2021-04-02 13:05:33.690494049 +0000
-@@ -95,9 +95,6 @@ enum { forward_and_append,	/* Forward an
+diff -ur dhcp-4.4.3.orig/relay/dhcrelay.c dhcp-4.4.3/relay/dhcrelay.c
+--- dhcp-4.4.3.orig/relay/dhcrelay.c	2022-03-08 09:26:03.000000000 +0000
++++ dhcp-4.4.3/relay/dhcrelay.c	2022-04-03 16:59:31.166092971 +0000
+@@ -95,9 +95,6 @@
         forward_untouched,	/* Forward without changes. */
         discard } agent_relay_mode = forward_and_replace;
  
--u_int16_t local_port;
--u_int16_t remote_port;
+-extern u_int16_t local_port;
+-extern u_int16_t remote_port;
 -
  /* Relay agent server list. */
  struct server_list {
  	struct server_list *next;
---- dhcp-4.4.2/server/mdb.c.extravars	2019-12-17 19:13:31.000000000 +0000
-+++ dhcp-4.4.2/server/mdb.c		2021-04-02 13:09:26.508311259 +0000
-@@ -67,8 +67,6 @@ static host_id_info_t *host_id_info = NU
+diff -ur dhcp-4.4.3.orig/server/mdb.c dhcp-4.4.3/server/mdb.c
+--- dhcp-4.4.3.orig/server/mdb.c	2022-03-08 09:26:03.000000000 +0000
++++ dhcp-4.4.3/server/mdb.c	2022-04-03 16:59:48.006131100 +0000
+@@ -67,8 +67,6 @@
  
  int numclasseswritten;
  
--omapi_object_type_t *dhcp_type_host;
+-extern omapi_object_type_t *dhcp_type_host;
 -
  isc_result_t enter_class(cd, dynamicp, commit)
  	struct class *cd;
diff --git a/dhcp-garbage-in-format-string-error.patch b/dhcp-garbage-in-format-string-error.patch
new file mode 100644
index 0000000..5844b73
--- /dev/null
+++ b/dhcp-garbage-in-format-string-error.patch
@@ -0,0 +1,26 @@
+From cfe6414644b68d5b6b5ba150bf57cff0a709a59e Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:28:13 +0100
+Subject: [PATCH 09/28] Fix 'garbage in format string' error
+
+RHBZ: 450042
+---
+ common/tables.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/common/tables.c b/common/tables.c
+index be37737..ce12fcd 100644
+--- a/common/tables.c
++++ b/common/tables.c
+@@ -222,7 +222,7 @@ static struct option dhcp_options[] = {
+ 	{ "name-service-search", "Sa",		&dhcp_universe, 117, 1 },
+ #endif
+ 	{ "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
+-- 
+2.35.1
+
diff --git a/dhcp-handle-null-timouet.patch b/dhcp-handle-null-timouet.patch
new file mode 100644
index 0000000..4659e0c
--- /dev/null
+++ b/dhcp-handle-null-timouet.patch
@@ -0,0 +1,31 @@
+From 7653f3ea80230d4b38bff1c65164aa18c6e51519 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:29:08 +0100
+Subject: [PATCH 10/28] Handle null timeout
+
+Handle cases in add_timeout() where the function is called with a NULL
+value for the 'when' parameter
+
+ISC-Bugs: #19867 (rejected)
+---
+ common/dispatch.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/common/dispatch.c b/common/dispatch.c
+index 7def34c..9741ff5 100644
+--- a/common/dispatch.c
++++ b/common/dispatch.c
+@@ -209,6 +209,10 @@ void add_timeout (when, where, what, ref, unref)
+ 	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) {
+-- 
+2.35.1
+
diff --git a/dhcp-hwaddress.patch b/dhcp-hwaddress.patch
new file mode 100644
index 0000000..8148980
--- /dev/null
+++ b/dhcp-hwaddress.patch
@@ -0,0 +1,100 @@
+From 908ea5f3a45a050a878de16d5acde6eda1b77d9f Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:42:50 +0100
+Subject: [PATCH 20/28] Discover all hwaddress for xid uniqueness
+
+---
+ common/discover.c |  2 ++
+ common/lpf.c      | 27 ++++++++++++++++++++++-----
+ includes/dhcpd.h  |  3 +++
+ 3 files changed, 27 insertions(+), 5 deletions(-)
+
+diff --git a/common/discover.c b/common/discover.c
+index b4b1959..96dcdcf 100644
+--- a/common/discover.c
++++ b/common/discover.c
+@@ -653,6 +653,8 @@ discover_interfaces(int state) {
+ 			interface_dereference(&tmp, MDL);
+ 			tmp = interfaces; /* XXX */
+ 		}
++		if (tmp != NULL)
++			try_hw_addr(tmp);
+ 
+ 		if (dhcp_interface_discovery_hook) {
+ 			(*dhcp_interface_discovery_hook)(tmp);
+diff --git a/common/lpf.c b/common/lpf.c
+index fcaa13d..77a5668 100644
+--- a/common/lpf.c
++++ b/common/lpf.c
+@@ -713,8 +713,22 @@ ioctl_get_ll(char *name)
+ 	return sll;
+ }
+ 
++// define ? 
++void try_hw_addr(struct interface_info *info){
++  get_hw_addr2(info);
++};
++
+ void
+ get_hw_addr(struct interface_info *info)
++{
++  if (get_hw_addr2(info) == ISC_R_NOTFOUND){
++    log_fatal("Unsupported device type for \"%s\"",
++              info->name);
++  }
++}
++
++isc_result_t
++get_hw_addr2(struct interface_info *info)
+ {
+ 	struct hardware *hw = &info->hw_address;
+ 	char *name = info->name;
+@@ -724,7 +738,8 @@ get_hw_addr(struct interface_info *info)
+ 	int sll_allocated = 0;
+ 	char *dup = NULL;
+ 	char *colon = NULL;
+-
++        isc_result_t result = ISC_R_SUCCESS;
++        
+ 	if (getifaddrs(&ifaddrs) == -1)
+ 		log_fatal("Failed to get interfaces");
+ 
+@@ -808,14 +823,16 @@ get_hw_addr(struct interface_info *info)
+ 			hw->hbuf[4] = 0xef;
+ 			break;
+ #endif
+-		default:
+-			freeifaddrs(ifaddrs);
+-			log_fatal("Unsupported device type %hu for \"%s\"",
+-				  sll->sll_hatype, name);
++        default:
++          log_error("Unsupported device type %hu for \"%s\"",
++                      sll->sll_hatype, name);
++          result = ISC_R_NOTFOUND;
++
+ 	}
+ 
+ 	if (sll_allocated)
+ 		dfree(sll, MDL);
+ 	freeifaddrs(ifaddrs);
++        return result;
+ }
+ #endif
+diff --git a/includes/dhcpd.h b/includes/dhcpd.h
+index e9e52e7..fabad01 100644
+--- a/includes/dhcpd.h
++++ b/includes/dhcpd.h
+@@ -2653,7 +2653,10 @@ void print_dns_status (int, struct dhcp_ddns_cb *, isc_result_t);
+ #endif
+ const char *print_time(TIME);
+ 
++
+ void get_hw_addr(struct interface_info *info);
++void try_hw_addr(struct interface_info *info);
++isc_result_t get_hw_addr2(struct interface_info *info);
+ char *buf_to_hex (const unsigned char *s, unsigned len,
+                    const char *file, int line);
+ char *format_lease_id(const unsigned char *s, unsigned len, int format,
+-- 
+2.35.1
+
diff --git a/dhcp-link-local-address.patch b/dhcp-link-local-address.patch
new file mode 100644
index 0000000..4011c9a
--- /dev/null
+++ b/dhcp-link-local-address.patch
@@ -0,0 +1,79 @@
+From 1f8681acba9ab70fbe17c85e5a1f4ce6a648b55d Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 28 Feb 2019 15:30:21 +0100
+Subject: [PATCH 22/28] dhclient: make sure link-local address is ready in
+ stateless mode
+
+Bug-url: https://bugzilla.redhat.com/1263466
+---
+ client/dhclient.c | 30 ++++++++++++++++++++----------
+ 1 file changed, 20 insertions(+), 10 deletions(-)
+
+diff --git a/client/dhclient.c b/client/dhclient.c
+index 6bbefc7..60836b4 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
+@@ -943,6 +943,12 @@ main(int argc, char **argv) {
+ 
+ 	inaddr_any.s_addr = INADDR_ANY;
+ 
++	/* Discover all the network interfaces. */
++	discover_interfaces(DISCOVER_UNCONFIGURED);
++
++	/* Parse the dhclient.conf file. */
++	read_client_conf();
++
+ 	/* Stateless special case. */
+ 	if (stateless) {
+ 		if (release_mode || (wanted_ia_na > 0) ||
+@@ -959,12 +965,6 @@ main(int argc, char **argv) {
+ 		finish(0);
+ 	}
+ 
+-	/* Discover all the network interfaces. */
+-	discover_interfaces(DISCOVER_UNCONFIGURED);
+-
+-	/* 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);
+@@ -1433,20 +1433,30 @@ void run_stateless(int exit_mode, u_int16_t port)
+ 	IGNORE_UNUSED(port);
+ #endif
+ 
+-	/* Discover the network interface. */
+-	discover_interfaces(DISCOVER_REQUESTED);
++	struct interface_info *ip;
+ 
+ 	if (!interfaces)
+ 		usage("No interfaces available for stateless command: %s", "-S");
+ 
+-	/* Parse the dhclient.conf file. */
+ #ifdef DHCP4o6
+ 	if (dhcpv4_over_dhcpv6) {
+ 		/* Mark we want to request IRT too! */
+ 		dhcpv4_over_dhcpv6++;
+ 	}
+ #endif
+-	read_client_conf();
++
++	for (ip = interfaces; ip; ip = ip->next) {
++		if ((interfaces_requested > 0) &&
++		    ((ip->flags & (INTERFACE_REQUESTED |
++				   INTERFACE_AUTOMATIC)) !=
++		     INTERFACE_REQUESTED))
++			continue;
++		script_init(ip->client, "PREINIT6", NULL);
++		script_go(ip->client);
++	}
++
++	/* Discover the network interface. */
++	discover_interfaces(DISCOVER_REQUESTED);
+ 
+ 	/* Parse the lease database. */
+ 	read_client_leases();
+-- 
+2.35.1
+
diff --git a/dhcp-lpf-ib.patch b/dhcp-lpf-ib.patch
new file mode 100644
index 0000000..b9b15e0
--- /dev/null
+++ b/dhcp-lpf-ib.patch
@@ -0,0 +1,625 @@
+From 90d64318e17df066c27b8e99ba6ab7f51154917b Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:34:21 +0100
+Subject: [PATCH 14/28] IPoIB support (#660681)
+
+(Submitted to dhcp-bugs at isc.org - [ISC-Bugs #24249])
+---
+ client/dhclient.c |  33 ++++++
+ common/bpf.c      |  32 ++++++
+ common/discover.c |   4 +-
+ common/lpf.c      | 274 ++++++++++++++++++++++++++++++++++++++++++----
+ common/socket.c   |   8 +-
+ includes/dhcpd.h  |   6 +-
+ 6 files changed, 329 insertions(+), 28 deletions(-)
+
+diff --git a/client/dhclient.c b/client/dhclient.c
+index a99e21f..48edddf 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
+@@ -211,6 +211,8 @@ static const char use_v6command[] = "Command not used for DHCPv4: %s";
+   
+ #define DHCLIENT_USAGEH "{--version|--help|-h}"
+ 
++static void setup_ib_interface(struct interface_info *ip);
++
+ static void
+ usage(const char *sfmt, const char *sarg)
+ {
+@@ -1213,6 +1215,14 @@ main(int argc, char **argv) {
+ 	}
+ 	srandom(seed);
+ 
++	/* 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);
++		}
++	}
++
+ 	/*
+ 	 * Establish a default DUID.  We always do so for v6 and
+ 	 * do so if desired for v4 via the -D or -i options
+@@ -1507,6 +1517,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 --git a/common/bpf.c b/common/bpf.c
+index aede242..812cac3 100644
+--- a/common/bpf.c
++++ b/common/bpf.c
+@@ -237,11 +237,43 @@ int dhcp_bpf_relay_filter_len =
+ 	sizeof dhcp_bpf_relay_filter / sizeof (struct bpf_insn);
+ #endif
+ 
++/* 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 = NULL;
+ #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 --git a/common/discover.c b/common/discover.c
+index ed338b4..e562225 100644
+--- a/common/discover.c
++++ b/common/discover.c
+@@ -899,7 +899,7 @@ discover_interfaces(int state) {
+ 				if_register_send(tmp);
+ 			} else {
+ 				/* get_hw_addr() was called by register. */
+-				get_hw_addr(tmp->name, &tmp->hw_address);
++				get_hw_addr(tmp);
+ 			}
+ 			break;
+ #ifdef DHCPv6
+@@ -912,7 +912,7 @@ discover_interfaces(int state) {
+ 				   so now we have to call it explicitly
+ 				   to not leave the hardware address unknown
+ 				   (some code expects it cannot be. */
+-				get_hw_addr(tmp->name, &tmp->hw_address);
++				get_hw_addr(tmp);
+ 			} else {
+ 				if_register_linklocal6(tmp);
+ 			}
+diff --git a/common/lpf.c b/common/lpf.c
+index bb8822a..fcaa13d 100644
+--- a/common/lpf.c
++++ b/common/lpf.c
+@@ -45,6 +45,17 @@
+ #include <sys/ioctl.h>
+ #include <sys/socket.h>
+ #include <net/if.h>
++#include <ifaddrs.h>
++
++/* 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
++};
++
+ #endif
+ 
+ #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
+@@ -78,10 +89,20 @@ int if_register_lpf (info)
+ 		struct sockaddr common;
+ 		} sa;
+ 	struct ifreq ifr;
++	int type;
++	int protocol;
++
++	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;
++	}
+ 
+ 	/* Make an LPF socket. */
+-	if ((sock = socket(PF_PACKET, SOCK_RAW,
+-			   htons((short)ETH_P_ALL))) < 0) {
++	if ((sock = socket(PF_PACKET, type, htons((short)protocol))) < 0) {
+ 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+ 		    errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+ 		    errno == EAFNOSUPPORT || errno == EINVAL) {
+@@ -104,6 +125,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 ||
+@@ -120,8 +142,6 @@ int if_register_lpf (info)
+ 
+ 	}
+ 
+-	get_hw_addr(info->name, &info->hw_address);
+-
+ 	return sock;
+ }
+ #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
+@@ -176,6 +196,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(RELAY_PORT)
+ extern struct sock_filter dhcp_bpf_relay_filter [];
+@@ -199,11 +221,12 @@ void if_register_receive (info)
+ #ifdef PACKET_AUXDATA
+ 	{
+ 	int 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) {
++		if (setsockopt(info->rfdesc, SOL_PACKET, PACKET_AUXDATA,
++			      &val, sizeof(val)) < 0) {
++			if (errno != ENOPROTOOPT) {
++				log_fatal ("Failed to set auxiliary packet data: %m");
++			}
+ 		}
+ 	}
+ 	}
+@@ -253,6 +276,18 @@ static void lpf_gen_filter_setup (info)
+ 
+ 	memset(&p, 0, sizeof(p));
+ 
++	if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++		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 (local_port);
++	} else {
++
+ 	/* Set up the bpf filter program structure.    This is defined in
+ 	   bpf.c */
+ 	p.len = dhcp_bpf_filter_len;
+@@ -275,6 +310,8 @@ static void lpf_gen_filter_setup (info)
+ #endif
+ 	dhcp_bpf_filter [8].k = ntohs (local_port);
+ 
++	}
++
+ 	if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
+ 			sizeof p) < 0) {
+ 		if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+@@ -330,6 +367,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;
+@@ -350,6 +435,11 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto)
+ 		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;
+ 
+@@ -370,6 +460,42 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto)
+ #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;
+@@ -408,6 +534,10 @@ ssize_t receive_packet (interface, buf, len, from, hfrom)
+ 	};
+ #endif /* PACKET_AUXDATA */
+ 
++	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;
+@@ -521,11 +651,33 @@ void maybe_setup_fallback ()
+ #endif
+ 
+ #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR)
+-void
+-get_hw_addr(const char *name, struct hardware *hw) {
++struct sockaddr_ll *
++get_ll (struct ifaddrs *ifaddrs, struct ifaddrs **ifa, char *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)
++			return (struct sockaddr_ll *)(void *)(*ifa)->ifa_addr;
++	}
++	*ifa = NULL;
++	return NULL;
++}
++
++struct sockaddr_ll *
++ioctl_get_ll(char *name)
++{
+ 	int sock;
+ 	struct ifreq tmp;
+-	struct sockaddr *sa;
++	struct sockaddr *sa = NULL;
++	struct sockaddr_ll *sll = NULL;
+ 
+ 	if (strlen(name) >= sizeof(tmp.ifr_name)) {
+ 		log_fatal("Device name too long: \"%s\"", name);
+@@ -542,13 +694,58 @@ get_hw_addr(const char *name, struct hardware *hw) {
+ 		log_fatal("Error getting hardware address for \"%s\": %m",
+ 			  name);
+ 	}
++	close(sock);
+ 
+ 	sa = &tmp.ifr_hwaddr;
+-	switch (sa->sa_family) {
++	// needs to be freed outside this function
++	sll = dmalloc (sizeof (struct sockaddr_ll), MDL);
++	if (!sll)
++		log_fatal("Unable to allocate memory for link layer address");
++	memcpy(&sll->sll_hatype, &sa->sa_family, sizeof (sll->sll_hatype));
++	memcpy(sll->sll_addr, sa->sa_data, sizeof (sll->sll_addr));
++	switch (sll->sll_hatype) {
++		case ARPHRD_INFINIBAND:
++			sll->sll_halen = HARDWARE_ADDR_LEN_IOCTL;
++			break;
++		default:
++			break;
++	}
++	return sll;
++}
++
++void
++get_hw_addr(struct interface_info *info)
++{
++	struct hardware *hw = &info->hw_address;
++	char *name = info->name;
++	struct ifaddrs *ifaddrs = NULL;
++	struct ifaddrs *ifa = NULL;
++	struct sockaddr_ll *sll = NULL;
++	int sll_allocated = 0;
++	char *dup = NULL;
++	char *colon = NULL;
++
++	if (getifaddrs(&ifaddrs) == -1)
++		log_fatal("Failed to get interfaces");
++
++	if ((sll = get_ll(ifaddrs, &ifa, name)) == NULL) {
++		/*
++		 * We were unable to get link-layer address for name.
++		 * Fall back to ioctl(SIOCGIFHWADDR).
++		 */
++		sll = ioctl_get_ll(name);
++		if (sll != NULL)
++			sll_allocated = 1;
++		else
++			// shouldn't happen
++			log_fatal("Unexpected internal error");
++	}
++
++	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
+@@ -556,18 +753,50 @@ get_hw_addr(const char *name, struct hardware *hw) {
+ #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 = 7;
+ 			hw->hbuf[0] = HTYPE_FDDI;
+-			memcpy(&hw->hbuf[1], sa->sa_data, 6);
++			memcpy(&hw->hbuf[1], sll->sll_addr, 6);
++			break;
++		case ARPHRD_INFINIBAND:
++			dup = strdup(name);
++			/* Aliased infiniband interface is special case where
++			 * neither get_ll() nor ioctl_get_ll() get's correct hw
++			 * address, so we have to truncate the :0 and run
++			 * get_ll() again for the rest.
++			*/
++			if ((colon = strchr(dup, ':')) != NULL) {
++				*colon = '\0';
++				if ((sll = get_ll(ifaddrs, &ifa, dup)) == NULL)
++					log_fatal("Error getting hardware address for \"%s\": %m", name);
++			}
++			free (dup);
++			/* For Infiniband, save the broadcast address and store
++			 * the port GUID into the hardware address.
++			 */
++			if (ifa && (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 = HARDWARE_ADDR_LEN_IOCTL + 1;
++			hw->hbuf[0] = HTYPE_INFINIBAND;
++			memcpy(&hw->hbuf[1],
++			       &sll->sll_addr[sll->sll_halen - HARDWARE_ADDR_LEN_IOCTL],
++			       HARDWARE_ADDR_LEN_IOCTL);
+ 			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("local_family != AF_INET6 for \"%s\"",
++					  name);
+ 			hw->hlen = 0;
+ 			hw->hbuf[0] = HTYPE_RESERVED;
+ 			/* 0xdeadbeef should never occur on the wire,
+@@ -580,10 +809,13 @@ get_hw_addr(const char *name, struct hardware *hw) {
+ 			break;
+ #endif
+ 		default:
+-			log_fatal("Unsupported device type %ld for \"%s\"",
+-				  (long int)sa->sa_family, name);
++			freeifaddrs(ifaddrs);
++			log_fatal("Unsupported device type %hu for \"%s\"",
++				  sll->sll_hatype, name);
+ 	}
+ 
+-	close(sock);
++	if (sll_allocated)
++		dfree(sll, MDL);
++	freeifaddrs(ifaddrs);
+ }
+ #endif
+diff --git a/common/socket.c b/common/socket.c
+index 3953eac..903d034 100644
+--- a/common/socket.c
++++ b/common/socket.c
+@@ -358,7 +358,7 @@ void if_register_send (info)
+ 	info->wfdesc = if_register_socket(info, AF_INET, 0, NULL);
+ 	/* 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. */
+@@ -421,7 +421,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",
+@@ -577,7 +577,7 @@ if_register6(struct interface_info *info, int do_multicast) {
+ 	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) {
+@@ -633,7 +633,7 @@ if_register_linklocal6(struct interface_info *info) {
+ 	info->rfdesc = sock;
+ 	info->wfdesc = sock;
+ 
+-	get_hw_addr(info->name, &info->hw_address);
++	get_hw_addr(info);
+ 
+ 	if (!quiet_interface_discovery) {
+ 		if (info->shared_network != NULL) {
+diff --git a/includes/dhcpd.h b/includes/dhcpd.h
+index 4c5e877..e9e52e7 100644
+--- a/includes/dhcpd.h
++++ b/includes/dhcpd.h
+@@ -485,6 +485,9 @@ struct packet {
+ 
+ #define HARDWARE_ADDR_LEN 20
+ 
++/* ioctl limits hardware addresses to 8 bytes */
++#define HARDWARE_ADDR_LEN_IOCTL	8
++
+ struct hardware {
+ 	u_int8_t hlen;
+ 	u_int8_t hbuf[HARDWARE_ADDR_LEN + 1];
+@@ -1380,6 +1383,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.
+ 					 */
+@@ -2649,7 +2653,7 @@ void print_dns_status (int, struct dhcp_ddns_cb *, isc_result_t);
+ #endif
+ const char *print_time(TIME);
+ 
+-void get_hw_addr(const char *name, struct hardware *hw);
++void get_hw_addr(struct interface_info *info);
+ char *buf_to_hex (const unsigned char *s, unsigned len,
+                    const char *file, int line);
+ char *format_lease_id(const unsigned char *s, unsigned len, int format,
+-- 
+2.35.1
+
diff --git a/dhcp-manpages.patch b/dhcp-manpages.patch
index 24d6972..451979c 100644
--- a/dhcp-manpages.patch
+++ b/dhcp-manpages.patch
@@ -1,38 +1,20 @@
-diff -up dhcp-4.3.5b1/client/dhclient.conf.5.man dhcp-4.3.5b1/client/dhclient.conf.5
---- dhcp-4.3.5b1/client/dhclient.conf.5.man	2016-08-26 20:19:53.000000000 +0200
-+++ dhcp-4.3.5b1/client/dhclient.conf.5	2016-09-12 17:09:23.243313514 +0200
-@@ -228,7 +228,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.
-@@ -736,6 +737,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 was used on a laptop running NetBSD
- 1.3, though the domains have been modified.
-diff -up dhcp-4.3.5b1/client/dhclient-script.8.man dhcp-4.3.5b1/client/dhclient-script.8
---- dhcp-4.3.5b1/client/dhclient-script.8.man	2016-08-26 20:19:53.000000000 +0200
-+++ dhcp-4.3.5b1/client/dhclient-script.8	2016-09-12 17:08:09.516254385 +0200
-@@ -45,7 +45,7 @@ customizations are needed, they should b
+From d359a7dc30e0423f9b90129291538cad1ee6a6d9 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:25:53 +0100
+Subject: [PATCH 06/28] Various man-page-only fixes
+
+---
+ client/dhclient-script.8 | 22 +++++++++++++++++++++-
+ client/dhclient.conf.5   | 14 +++++++++++++-
+ common/dhcp-options.5    | 15 +++++++++++++++
+ server/dhcpd.conf.5      | 14 +++++++++-----
+ 4 files changed, 58 insertions(+), 7 deletions(-)
+
+diff --git a/client/dhclient-script.8 b/client/dhclient-script.8
+index 5e5bd3d..37ecdc5 100644
+--- a/client/dhclient-script.8
++++ b/client/dhclient-script.8
+@@ -43,7 +43,7 @@ customizations are needed, they should be possible using the enter and
  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
@@ -41,7 +23,7 @@ diff -up dhcp-4.3.5b1/client/dhclient-script.8.man dhcp-4.3.5b1/client/dhclient-
  .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
-@@ -89,6 +89,26 @@ present.   The
+@@ -87,6 +87,26 @@ present.   The
  .B ETCDIR/dhclient-exit-hooks
  script can modify the valid of exit_status to change the exit status
  of dhclient-script.
@@ -68,10 +50,43 @@ diff -up dhcp-4.3.5b1/client/dhclient-script.8.man dhcp-4.3.5b1/client/dhclient-
  .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.3.5b1/common/dhcp-options.5.man dhcp-4.3.5b1/common/dhcp-options.5
---- dhcp-4.3.5b1/common/dhcp-options.5.man	2016-08-26 20:19:53.000000000 +0200
-+++ dhcp-4.3.5b1/common/dhcp-options.5	2016-09-12 17:08:09.517254386 +0200
-@@ -1013,6 +1013,21 @@ classless IP routing - it does not inclu
+diff --git a/client/dhclient.conf.5 b/client/dhclient.conf.5
+index dbe6f7e..8bac980 100644
+--- a/client/dhclient.conf.5
++++ b/client/dhclient.conf.5
+@@ -228,7 +228,8 @@ responding to the client send the client its values for the specified
+ 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.
+@@ -735,6 +736,17 @@ broadcast packets transmitted by DHCP clients, but is only useful if you
+ know the DHCP service(s) anycast MAC address prior to configuring your
+ 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 was used on a laptop running NetBSD
+diff --git a/common/dhcp-options.5 b/common/dhcp-options.5
+index 51f80f7..a784b32 100644
+--- a/common/dhcp-options.5
++++ b/common/dhcp-options.5
+@@ -1075,6 +1075,21 @@ classless IP routing - it does not include a subnet mask.  Since
  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.
@@ -93,10 +108,11 @@ diff -up dhcp-4.3.5b1/common/dhcp-options.5.man dhcp-4.3.5b1/common/dhcp-options
  .RE
  .PP
  .nf
-diff -up dhcp-4.3.5b1/server/dhcpd.conf.5.man dhcp-4.3.5b1/server/dhcpd.conf.5
---- dhcp-4.3.5b1/server/dhcpd.conf.5.man	2016-08-26 20:19:53.000000000 +0200
-+++ dhcp-4.3.5b1/server/dhcpd.conf.5	2016-09-12 17:10:11.205351980 +0200
-@@ -528,6 +528,9 @@ pool {
+diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5
+index 691e5dd..b7e79ea 100644
+--- a/server/dhcpd.conf.5
++++ b/server/dhcpd.conf.5
+@@ -527,6 +527,9 @@ pool {
  };
  .fi
  .PP
@@ -106,7 +122,7 @@ diff -up dhcp-4.3.5b1/server/dhcpd.conf.5.man dhcp-4.3.5b1/server/dhcpd.conf.5
  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
-@@ -542,9 +545,9 @@ primary server might look like this:
+@@ -541,9 +544,9 @@ primary server might look like this:
  failover peer "foo" {
    primary;
    address anthrax.rc.example.com;
@@ -118,7 +134,7 @@ diff -up dhcp-4.3.5b1/server/dhcpd.conf.5.man dhcp-4.3.5b1/server/dhcpd.conf.5
    max-response-delay 60;
    max-unacked-updates 10;
    mclt 3600;
-@@ -1246,7 +1249,7 @@ the zone containing PTR records - for IS
+@@ -1323,7 +1326,7 @@ the zone containing PTR records - for ISC BIND, something like this:
  .PP
  .nf
  key DHCP_UPDATER {
@@ -127,7 +143,7 @@ diff -up dhcp-4.3.5b1/server/dhcpd.conf.5.man dhcp-4.3.5b1/server/dhcpd.conf.5
    secret pRP5FapFoJ95JEL06sv4PQ==;
  };
  
-@@ -1269,7 +1272,7 @@ dhcpd.conf file:
+@@ -1346,7 +1349,7 @@ dhcpd.conf file:
  .PP
  .nf
  key DHCP_UPDATER {
@@ -136,7 +152,7 @@ diff -up dhcp-4.3.5b1/server/dhcpd.conf.5.man dhcp-4.3.5b1/server/dhcpd.conf.5
    secret pRP5FapFoJ95JEL06sv4PQ==;
  };
  
-@@ -2742,7 +2745,8 @@ statement
+@@ -2918,7 +2921,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
@@ -146,3 +162,35 @@ diff -up dhcp-4.3.5b1/server/dhcpd.conf.5.man dhcp-4.3.5b1/server/dhcpd.conf.5
  .RE
  .PP
  The
+-- 
+2.35.1
+
+From aa328eef58ff93110f2a52cb3a80002ab8cee36e Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Tue, 22 Oct 2019 16:28:04 +0200
+Subject: [PATCH 26/28] Add dhclient(5) -B option description
+
+Bug-Url: https://bugzilla.redhat.com/1764088
+---
+ client/dhclient.8 | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/client/dhclient.8 b/client/dhclient.8
+index bacf3bc..76f0cc0 100644
+--- a/client/dhclient.8
++++ b/client/dhclient.8
+@@ -553,6 +553,11 @@ Path to the network configuration script invoked by
+ when it gets a lease.  If unspecified, the default
+ .B CLIENTBINDIR/dhclient-script
+ is used.  See \fBdhclient-script(8)\fR for a description of this file.
++.TP
++.BI \-B
++Always set the bootp broadcast flag in request packets, so that
++servers will always broadcast replies. This option is provided as
++an extension to enable dhclient to work on IBM s390 Linux guests.
+ .PP
+ .SH PORTS
+ During operations the client may use multiple UDP ports
+-- 
+2.35.1
+
diff --git a/dhcp-no-subnet-error2info.patch b/dhcp-no-subnet-error2info.patch
new file mode 100644
index 0000000..ec608cd
--- /dev/null
+++ b/dhcp-no-subnet-error2info.patch
@@ -0,0 +1,62 @@
+From 840c4f2175d14fa485f2a5e50a005847940b7e1f Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:40:51 +0100
+Subject: [PATCH 18/28] No subnet declaration for <iface>' should be info, not
+ error.
+
+---
+ common/discover.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/common/discover.c b/common/discover.c
+index e562225..b4b1959 100644
+--- a/common/discover.c
++++ b/common/discover.c
+@@ -806,9 +806,9 @@ discover_interfaces(int state) {
+ 
+ 		/* We must have a subnet declaration for each interface. */
+ 		if (!tmp->shared_network && (state == DISCOVER_SERVER)) {
+-			log_error("%s", "");
++			log_info("%s", "");
+ 			if (local_family == AF_INET) {
+-				log_error("No subnet declaration for %s (%s).",
++				log_info("No subnet declaration for %s (%s).",
+ 					  tmp->name,
+ 					  (tmp->addresses == NULL) ?
+ 					   "no IPv4 addresses" :
+@@ -823,26 +823,26 @@ discover_interfaces(int state) {
+ 				} else {
+ 					strcpy(abuf, "no IPv6 addresses");
+ 				}
+-				log_error("No subnet6 declaration for %s (%s).",
++				log_info("No subnet6 declaration for %s (%s).",
+ 					  tmp->name,
+ 					  abuf);
+ #endif /* DHCPv6 */
+ 			}
+ 			if (supports_multiple_interfaces(tmp)) {
+-				log_error ("** Ignoring requests on %s.  %s",
++				log_info ("** Ignoring requests on %s.  %s",
+ 					   tmp -> name, "If this is not what");
+-				log_error ("   you want, please write %s",
++				log_info ("   you want, please write %s",
+ #ifdef DHCPv6
+ 				           (local_family != AF_INET) ?
+ 					   "a subnet6 declaration" :
+ #endif
+ 					   "a subnet declaration");
+-				log_error ("   in your dhcpd.conf file %s",
++				log_info ("   in your dhcpd.conf file %s",
+ 					   "for the network segment");
+-				log_error ("   to %s %s %s",
++				log_info ("   to %s %s %s",
+ 					   "which interface",
+ 					   tmp -> name, "is attached. **");
+-				log_error ("%s", "");
++				log_info ("%s", "");
+ 				goto next;
+ 			} else {
+ 				log_error ("You must write a %s",
+-- 
+2.35.1
+
diff --git a/dhcp-option97-pxe-client-id.patch b/dhcp-option97-pxe-client-id.patch
new file mode 100644
index 0000000..f254eb6
--- /dev/null
+++ b/dhcp-option97-pxe-client-id.patch
@@ -0,0 +1,246 @@
+From f01a29a90269c98a86accb0923d65aecf5f59b44 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 28 Feb 2019 16:40:38 +0100
+Subject: [PATCH 23/28] option 97 - pxe-client-id
+
+Bug-url: https://bugzilla.redhat.com/1058674
+ISC-Bugs #38110
+---
+ common/options.c        | 27 ++++++++++++++++++++-------
+ common/tables.c         |  3 ++-
+ includes/dhcp.h         |  1 +
+ server/dhcp.c           | 19 +++++++++++++++++++
+ server/dhcpd.conf.5     |  9 ++++++---
+ server/dhcpleasequery.c | 18 +++++++++++++++---
+ server/failover.c       |  3 +++
+ server/mdb.c            |  5 +++--
+ 8 files changed, 69 insertions(+), 16 deletions(-)
+
+diff --git a/common/options.c b/common/options.c
+index 66433c4..4e26094 100644
+--- a/common/options.c
++++ b/common/options.c
+@@ -4551,13 +4551,26 @@ int validate_packet(struct packet *packet)
+ 				"a future version of ISC DHCP will reject this");
+ 		}
+ 	} else {
+-		/*
+-		 * If hlen is 0 we don't have any identifier, we warn the user
+-		 * but continue processing the packet as we can.
+-		 */
+-		if (packet->raw->hlen == 0) {
+-			log_debug("Received DHCPv4 packet without client-id"
+-				  " option and empty hlen field.");
++		oc = lookup_option (&dhcp_universe, packet->options,
++				    DHO_PXE_CLIENT_ID);
++		if (oc) {
++			/* Let's check if pxe-client-id is sane */
++			if ((oc->data.len < 2) ||
++			    (oc->data.data[0] == '\0' &&
++			     oc->data.len != 17)) {
++				log_debug("Dropped DHCPv4 packet with wrong "
++				    "(len == %d) pxe-client-id", oc->data.len);
++				return (0);
++			}
++		} else {
++			/*
++			 * If hlen is 0 we don't have any identifier, we warn the user
++			 * but continue processing the packet as we can.
++			 */
++			if (packet->raw->hlen == 0) {
++				log_debug("Received DHCPv4 packet without client-id"
++						" option and empty hlen field.");
++			}
+ 		}
+ 	}
+ 
+diff --git a/common/tables.c b/common/tables.c
+index 96521a6..8034d94 100644
+--- a/common/tables.c
++++ b/common/tables.c
+@@ -200,8 +200,9 @@ static struct option dhcp_options[] = {
+ 	/* Defined by RFC 4578 */
+ 	{ "pxe-system-type", "Sa",		&dhcp_universe,  93, 1 },
+ 	{ "pxe-interface-id", "BBB",		&dhcp_universe,  94, 1 },
+-	{ "pxe-client-id", "BX",		&dhcp_universe,  97, 1 },
+ #endif
++	{ "pxe-client-id", "BX",		&dhcp_universe,  97, 1 },
++
+ 	{ "uap-servers", "t",			&dhcp_universe,  98, 1 },
+ #if defined(RFC4776_OPTIONS)
+         { "geoconf-civic", "X",                 &dhcp_universe, 99, 1 },
+diff --git a/includes/dhcp.h b/includes/dhcp.h
+index 7202f1d..4ad3874 100644
+--- a/includes/dhcp.h
++++ b/includes/dhcp.h
+@@ -158,6 +158,7 @@ struct dhcp_packet {
+ #define DHO_AUTHENTICATE			90  /* RFC3118, was 210 */
+ #define DHO_CLIENT_LAST_TRANSACTION_TIME	91
+ #define DHO_ASSOCIATED_IP			92
++#define DHO_PXE_CLIENT_ID			97  /* RFC4578 */
+ #define DHO_V6_ONLY_PREFERRED			108 /* RFC8925 */
+ #define DHO_SUBNET_SELECTION			118 /* RFC3011! */
+ #define DHO_DOMAIN_SEARCH			119 /* RFC3397 */
+diff --git a/server/dhcp.c b/server/dhcp.c
+index 8363840..29d9c69 100644
+--- a/server/dhcp.c
++++ b/server/dhcp.c
+@@ -228,6 +228,10 @@ dhcp (struct packet *packet) {
+ 		if (lease -> uid_len) {
+ 			oc = lookup_option (&dhcp_universe, packet -> options,
+ 					    DHO_DHCP_CLIENT_IDENTIFIER);
++			if (!oc)
++				oc = lookup_option (&dhcp_universe,
++						    packet -> options,
++						    DHO_PXE_CLIENT_ID);
+ 			if (!oc)
+ 				goto nolease;
+ 
+@@ -826,6 +830,9 @@ void dhcprelease (packet, ms_nulltp)
+ 
+ 	oc = lookup_option (&dhcp_universe, packet -> options,
+ 			    DHO_DHCP_CLIENT_IDENTIFIER);
++	if (!oc)
++		oc = lookup_option (&dhcp_universe, packet -> options,
++				    DHO_PXE_CLIENT_ID);
+ 	memset (&data, 0, sizeof data);
+ 	if (oc &&
+ 	    evaluate_option_cache (&data, packet, (struct lease *)0,
+@@ -1338,6 +1345,9 @@ void dhcpinform (packet, ms_nulltp)
+          */
+ 	oc = lookup_option(&dhcp_universe, packet->options,
+ 			   DHO_DHCP_CLIENT_IDENTIFIER);
++	if (!oc)
++		oc = lookup_option (&dhcp_universe, packet -> options,
++				    DHO_PXE_CLIENT_ID);
+ 	memset(&d1, 0, sizeof(d1));
+ 	if (oc &&
+ 	    evaluate_option_cache(&d1, packet, NULL, NULL,
+@@ -2448,6 +2458,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
+ 		   can be used. */
+ 		oc = lookup_option (&dhcp_universe, packet -> options,
+ 				    DHO_DHCP_CLIENT_IDENTIFIER);
++		if (!oc)
++			oc = lookup_option (&dhcp_universe, packet -> options,
++					    DHO_PXE_CLIENT_ID);
+ 		if (oc &&
+ 		    evaluate_option_cache (&d1, packet, lease,
+ 					   (struct client_state *)0,
+@@ -3040,6 +3053,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
+ 		/* Record the uid, if given... */
+ 		oc = lookup_option (&dhcp_universe, packet -> options,
+ 				    DHO_DHCP_CLIENT_IDENTIFIER);
++		if (!oc)
++			oc = lookup_option (&dhcp_universe, packet -> options,
++					    DHO_PXE_CLIENT_ID);
+ 		if (oc &&
+ 		    evaluate_option_cache(&d1, packet, lease, NULL,
+ 					  packet->options, state->options,
+@@ -4258,6 +4274,9 @@ int find_lease (struct lease **lp,
+ 	   specified unique client identifier. */
+ 	oc = lookup_option (&dhcp_universe, packet -> options,
+ 			    DHO_DHCP_CLIENT_IDENTIFIER);
++	if (!oc)
++		oc = lookup_option (&dhcp_universe, packet -> options,
++				    DHO_PXE_CLIENT_ID);
+ 	memset (&client_identifier, 0, sizeof client_identifier);
+ 	if (oc &&
+ 	    evaluate_option_cache (&client_identifier,
+diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5
+index b7e79ea..2354b1d 100644
+--- a/server/dhcpd.conf.5
++++ b/server/dhcpd.conf.5
+@@ -1664,10 +1664,12 @@ should be a name identifying the host.  If a \fIhostname\fR option is
+ not specified for the host, \fIhostname\fR is used.
+ .PP
+ \fIHost\fR declarations are matched to actual DHCP or BOOTP clients
+-by matching the \fRdhcp-client-identifier\fR option specified in the
++by matching the \fIdhcp-client-identifier\fR or \fIpxe-client-id\fR
++options specified in the
+ \fIhost\fR declaration to the one supplied by the client, or, if the
+ \fIhost\fR declaration or the client does not provide a
+-\fRdhcp-client-identifier\fR option, by matching the \fIhardware\fR
++\fIdhcp-client-identifier\fR or \fIpxe-client-id\fR options,
++by matching the \fIhardware\fR
+ parameter in the \fIhost\fR declaration to the network hardware
+ address supplied by the client.  BOOTP clients do not normally
+ provide a \fIdhcp-client-identifier\fR, so the hardware address must
+@@ -1679,7 +1681,8 @@ to identify hosts.
+ .PP
+ Please be aware that
+ .B only
+-the \fIdhcp-client-identifier\fR option and the hardware address can be
++the \fIdhcp-client-identifier\fR and \fIpxe-client-id\fR
++options and the hardware address can be
+ used to match a host declaration, or the \fIhost-identifier option\fR
+ parameter for DHCPv6 servers.  For example, it is not possible to
+ match a host declaration to a \fIhost-name\fR option.  This is
+diff --git a/server/dhcpleasequery.c b/server/dhcpleasequery.c
+index 0f1d4f7..dae4ae7 100644
+--- a/server/dhcpleasequery.c
++++ b/server/dhcpleasequery.c
+@@ -276,7 +276,7 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
+ 		 */
+ 
+ 		memset(&uid, 0, sizeof(uid));
+-		if (get_option(&uid, 
++		i = get_option(&uid,
+ 			       &dhcp_universe,
+ 			       packet,
+ 			       NULL,
+@@ -286,8 +286,20 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
+ 			       packet->options, 
+ 			       &global_scope,
+ 			       DHO_DHCP_CLIENT_IDENTIFIER,
+-			       MDL)) {
+-
++			       MDL);
++		if (!i)
++			i = get_option(&uid,
++				       &dhcp_universe,
++				       packet,
++				       NULL,
++				       NULL,
++				       packet->options,
++				       NULL,
++				       packet->options,
++				       &global_scope,
++				       DHO_PXE_CLIENT_ID,
++				       MDL);
++		if (i) {
+ 			snprintf(dbg_info, 
+ 				 sizeof(dbg_info), 
+ 				 "client-id %s",
+diff --git a/server/failover.c b/server/failover.c
+index 5b36d3a..a641e86 100644
+--- a/server/failover.c
++++ b/server/failover.c
+@@ -5988,6 +5988,9 @@ int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state)
+ 
+ 	oc = lookup_option(&dhcp_universe, packet->options,
+ 			   DHO_DHCP_CLIENT_IDENTIFIER);
++	if (!oc)
++		oc = lookup_option(&dhcp_universe, packet -> options,
++				    DHO_PXE_CLIENT_ID);
+ 	memset(&ds, 0, sizeof ds);
+ 	if (oc &&
+ 	    evaluate_option_cache(&ds, packet, NULL, NULL,
+diff --git a/server/mdb.c b/server/mdb.c
+index 60a40e1..2cd5605 100644
+--- a/server/mdb.c
++++ b/server/mdb.c
+@@ -129,8 +129,9 @@ static int find_uid_statement (struct executable_statement *esp,
+ 	    esp -> data.option &&
+ 	    (esp -> data.option -> option -> universe ==
+ 	     &dhcp_universe) &&
+-	    (esp -> data.option -> option -> code ==
+-	     DHO_DHCP_CLIENT_IDENTIFIER)) {
++	    ((esp -> data.option -> option -> code ==
++						DHO_DHCP_CLIENT_IDENTIFIER) ||
++	     (esp -> data.option -> option -> code == DHO_PXE_CLIENT_ID))) {
+ 		if (condp) {
+ 			log_error ("dhcp client identifier may not be %s",
+ 				   "specified conditionally.");
+-- 
+2.35.1
+
diff --git a/dhcp-options.patch b/dhcp-options.patch
index db42719..4b5696b 100644
--- a/dhcp-options.patch
+++ b/dhcp-options.patch
@@ -1,6 +1,21 @@
-diff -urNp -x '*.orig' dhcp-4.4.2.org/client/clparse.c dhcp-4.4.2/client/clparse.c
---- dhcp-4.4.2.org/client/clparse.c	2020-01-21 20:21:48.000000000 +0100
-+++ dhcp-4.4.2/client/clparse.c	2021-05-15 22:10:03.054906758 +0200
+From af18c830fe55f6be0b89997a36b611d981e3c25d Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:19:47 +0100
+Subject: [PATCH 02/28] additional dhclient options
+
+---
+ client/clparse.c    |  10 +-
+ client/dhclient.8   |  27 +++++
+ client/dhclient.c   | 271 +++++++++++++++++++++++++++++++++++++++++++-
+ common/conflex.c    |   2 +
+ includes/dhcpd.h    |   3 +
+ includes/dhctoken.h |   3 +-
+ 6 files changed, 309 insertions(+), 7 deletions(-)
+
+diff --git a/client/clparse.c b/client/clparse.c
+index 74ca499..bb63825 100644
+--- a/client/clparse.c
++++ b/client/clparse.c
 @@ -192,6 +192,7 @@ isc_result_t read_client_conf ()
  	/* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
  	 */
@@ -19,7 +34,7 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/clparse.c dhcp-4.4.2/client/clparse
  
  void parse_client_statement (cfile, ip, config)
  	struct parse *cfile;
-@@ -820,6 +822,12 @@ void parse_client_statement (cfile, ip,
+@@ -820,6 +822,12 @@ void parse_client_statement (cfile, ip, config)
  		parse_lease_id_format(cfile);
  		break;
  
@@ -32,11 +47,12 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/clparse.c dhcp-4.4.2/client/clparse
  
  	      default:
  		lose = 0;
-diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.8 dhcp-4.4.2/client/dhclient.8
---- dhcp-4.4.2.org/client/dhclient.8	2020-01-21 20:21:48.000000000 +0100
-+++ dhcp-4.4.2/client/dhclient.8	2021-05-15 22:10:03.054906758 +0200
-@@ -147,6 +147,33 @@ dhclient - Dynamic Host Configuration Pr
- .I seconds
+diff --git a/client/dhclient.8 b/client/dhclient.8
+index 861ff56..5029dac 100644
+--- a/client/dhclient.8
++++ b/client/dhclient.8
+@@ -135,6 +135,33 @@ dhclient - Dynamic Host Configuration Protocol Client
+ .B -w
  ]
  [
 +.B -B
@@ -66,82 +82,13 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.8 dhcp-4.4.2/client/dhclie
 +.I timeout
 +]
 +[
- .B -v
+ .B --dad-wait-time
+ .I seconds
  ]
- [
-@@ -302,6 +329,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 \-C\ <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 \--request-options\ <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 --request-options
-+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 --request-options
-+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 -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.c dhcp-4.4.2/client/dhclient.c
---- dhcp-4.4.2.org/client/dhclient.c	2021-05-15 22:10:02.951572212 +0200
-+++ dhcp-4.4.2/client/dhclient.c	2021-05-15 22:10:03.054906758 +0200
+diff --git a/client/dhclient.c b/client/dhclient.c
+index 46dc3a7..6c1c09a 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
 @@ -41,6 +41,12 @@
  #include <sys/wait.h>
  #include <limits.h>
@@ -155,7 +102,7 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.c dhcp-4.4.2/client/dhclie
  TIME default_lease_time = 43200; /* 12 hours... */
  TIME max_lease_time = 86400; /* 24 hours... */
  
-@@ -112,6 +118,10 @@ char *mockup_relay = NULL;
+@@ -113,6 +119,10 @@ char *mockup_relay = NULL;
  
  char *progname = NULL;
  
@@ -166,25 +113,27 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.c dhcp-4.4.2/client/dhclie
  void run_stateless(int exit_mode, u_int16_t port);
  
  static isc_result_t write_duid(struct data_string *duid);
-@@ -188,7 +198,11 @@ static const char use_v6command[] = "Com
+@@ -189,8 +199,12 @@ static const char use_v6command[] = "Command not used for DHCPv4: %s";
  "                [-s server-addr] [-cf config-file]\n" \
  "                [-df duid-file] [-lf lease-file]\n" \
  "                [-pf pid-file] [--no-pid] [-e VAR=val]\n" \
 -"                [-sf script-file] [interface]*"
+-
 +"                [-sf script-file] [interface]*\n" \
 +"                [-C <dhcp-client-identifier>] [-B]\n" \
 +"                [-H <host-name> | -F <fqdn.fqdn>] [--timeout <timeout>]\n" \
 +"                [-V <vendor-class-identifier>]\n" \
 +"                [--request-options <request option list>]"
- 
++  
  #define DHCLIENT_USAGEH "{--version|--help|-h}"
  
-@@ -251,6 +265,17 @@ main(int argc, char **argv) {
- 	/* Initialize client globals. */
- 	memset(&default_duid, 0, sizeof(default_duid));
- 
-+	char *dhcp_client_identifier_arg = NULL;
-+	char *dhcp_host_name_arg = NULL;
+ static void
+@@ -249,6 +263,16 @@ main(int argc, char **argv) {
+ #else
+ 	progname = argv[0];
+ #endif
++        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;
@@ -193,14 +142,13 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.c dhcp-4.4.2/client/dhclie
 +	char *arg_conf = NULL;
 +	int arg_conf_len = 0;
 +
-+
- 	/* 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. */
-@@ -305,6 +330,89 @@ main(int argc, char **argv) {
- 					 strlen(DHCLIENT_USAGEH)));
- 			IGNORE_RET(write(STDERR_FILENO, "\n", 1));
- 			exit(0);
+ 	/* Initialize client globals. */
+ 	memset(&default_duid, 0, sizeof(default_duid));
+ 
+@@ -564,6 +588,89 @@ main(int argc, char **argv) {
+ 			std_dhcid = 1;
+ 		} else if (!strcmp(argv[i], "-v")) {
+ 			quiet = 0;
 +		} else if (!strcmp(argv[i], "-C")) {
 +			if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
 +				usage(use_noarg, argv[i-1]);
@@ -284,10 +232,10 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.c dhcp-4.4.2/client/dhclie
 +
 +			dhclient_request_options = argv[i];
 +
- 		}
- 	}
- 	/* When not forbidden prepare to become a daemon */
-@@ -831,6 +939,156 @@ main(int argc, char **argv) {
+ 		} else if (argv[i][0] == '-') {
+ 			usage("Unknown command: %s", argv[i]);
+ 		} else if (interfaces_requested < 0) {
+@@ -760,6 +867,156 @@ main(int argc, char **argv) {
  	/* Parse the dhclient.conf file. */
  	read_client_conf();
  
@@ -444,46 +392,7 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.c dhcp-4.4.2/client/dhclie
  	/* Parse the lease database. */
  	read_client_leases();
  
-@@ -991,7 +1249,7 @@ main(int argc, char **argv) {
- 						 *whole seconds
- 						 */
- 						add_timeout(&tv, state_reboot,
--						            client, 0, 0);
-+							    client, 0, 0);
- 					} else {
- 						state_reboot(client);
- 					}
-@@ -1771,11 +2029,11 @@ void bootp (packet)
- 	     ap; ap = ap -> next) {
- 		if (addr_match(&packet->client_addr, &ap->match)) {
- 
--		        /* piaddr() returns its result in a static
-+			/* piaddr() returns its result in a static
- 			   buffer sized 4*16 (see common/inet.c). */
- 
--		        strcpy(addrbuf, piaddr(ap->match.addr));
--		        strcpy(maskbuf, piaddr(ap->match.mask));
-+			strcpy(addrbuf, piaddr(ap->match.addr));
-+			strcpy(maskbuf, piaddr(ap->match.mask));
- 
- 			log_info("BOOTREPLY from %s rejected by rule %s "
- 				 "mask %s.", piaddr(packet->client_addr),
-@@ -1823,11 +2081,11 @@ void dhcp (packet)
- 	     ap; ap = ap -> next) {
- 		if (addr_match(&packet->client_addr, &ap->match)) {
- 
--		        /* piaddr() returns its result in a static
-+			/* piaddr() returns its result in a static
- 			   buffer sized 4*16 (see common/inet.c). */
- 
--		        strcpy(addrbuf, piaddr(ap->match.addr));
--		        strcpy(maskbuf, piaddr(ap->match.mask));
-+			strcpy(addrbuf, piaddr(ap->match.addr));
-+			strcpy(maskbuf, piaddr(ap->match.mask));
- 
- 			log_info("%s from %s rejected by rule %s mask %s.",
- 				 type, piaddr(packet->client_addr),
-@@ -3403,7 +3661,8 @@ void make_discover (client, lease)
+@@ -3472,7 +3729,8 @@ void make_discover (client, lease)
  	client -> packet.xid = random ();
  	client -> packet.secs = 0; /* filled in by send_discover. */
  
@@ -493,7 +402,7 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.c dhcp-4.4.2/client/dhclie
  		client -> packet.flags = 0;
  	else
  		client -> packet.flags = htons (BOOTP_BROADCAST);
-@@ -3488,7 +3747,9 @@ void make_request (client, lease)
+@@ -3557,7 +3815,9 @@ void make_request (client, lease)
  	} else {
  		memset (&client -> packet.ciaddr, 0,
  			sizeof client -> packet.ciaddr);
@@ -504,7 +413,7 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.c dhcp-4.4.2/client/dhclie
  			client -> packet.flags = 0;
  		else
  			client -> packet.flags = htons (BOOTP_BROADCAST);
-@@ -3551,7 +3812,8 @@ void make_decline (client, lease)
+@@ -3620,7 +3880,8 @@ void make_decline (client, lease)
  	client -> packet.hops = 0;
  	client -> packet.xid = client -> xid;
  	client -> packet.secs = 0; /* Filled in by send_request. */
@@ -514,10 +423,11 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/client/dhclient.c dhcp-4.4.2/client/dhclie
  		client -> packet.flags = 0;
  	else
  		client -> packet.flags = htons (BOOTP_BROADCAST);
-diff -urNp -x '*.orig' dhcp-4.4.2.org/common/conflex.c dhcp-4.4.2/common/conflex.c
---- dhcp-4.4.2.org/common/conflex.c	2020-01-21 20:21:48.000000000 +0100
-+++ dhcp-4.4.2/common/conflex.c	2021-05-15 22:10:03.054906758 +0200
-@@ -832,6 +832,8 @@ intern(char *atom, enum dhcp_token dfv)
+diff --git a/common/conflex.c b/common/conflex.c
+index 8b01dfb..1fa2be3 100644
+--- a/common/conflex.c
++++ b/common/conflex.c
+@@ -832,6 +832,8 @@ intern(char *atom, enum dhcp_token dfv) {
  		if (!strcasecmp(atom+1, "ig-endian")) {
  			return TOKEN_BIG_ENDIAN;
  		}
@@ -526,10 +436,11 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/common/conflex.c dhcp-4.4.2/common/conflex
  		break;
  	      case 'c':
  		if (!strcasecmp(atom + 1, "ase"))
-diff -urNp -x '*.orig' dhcp-4.4.2.org/includes/dhcpd.h dhcp-4.4.2/includes/dhcpd.h
---- dhcp-4.4.2.org/includes/dhcpd.h	2021-05-15 22:10:02.951572212 +0200
-+++ dhcp-4.4.2/includes/dhcpd.h	2021-05-15 22:10:03.054906758 +0200
-@@ -1279,6 +1279,9 @@ struct client_config {
+diff --git a/includes/dhcpd.h b/includes/dhcpd.h
+index f68b228..3b2e2ca 100644
+--- a/includes/dhcpd.h
++++ b/includes/dhcpd.h
+@@ -1284,6 +1284,9 @@ struct client_config {
  
  	int lease_id_format;		/* format for IDs in lease file,
  					   TOKEN_OCTAL or TOKEN_HEX */
@@ -539,16 +450,20 @@ diff -urNp -x '*.orig' dhcp-4.4.2.org/includes/dhcpd.h dhcp-4.4.2/includes/dhcpd
  };
  
  /* Per-interface state used in the dhcp client... */
-diff -urNp -x '*.orig' dhcp-4.4.2.org/includes/dhctoken.h dhcp-4.4.2/includes/dhctoken.h
---- dhcp-4.4.2.org/includes/dhctoken.h	2020-01-21 20:21:48.000000000 +0100
-+++ dhcp-4.4.2/includes/dhctoken.h	2021-05-15 22:10:03.054906758 +0200
-@@ -376,7 +376,8 @@ enum dhcp_token {
- 	LEASE_ID_FORMAT = 676,
+diff --git a/includes/dhctoken.h b/includes/dhctoken.h
+index e6d125f..6daa422 100644
+--- a/includes/dhctoken.h
++++ b/includes/dhctoken.h
+@@ -377,7 +377,8 @@ enum dhcp_token {
  	TOKEN_HEX = 677,
  	TOKEN_OCTAL = 678,
--	KEY_ALGORITHM = 679
-+	KEY_ALGORITHM = 679,
-+	BOOTP_BROADCAST_ALWAYS = 680
+ 	KEY_ALGORITHM = 679,
+-	DISCONNECT = 680
++	BOOTP_BROADCAST_ALWAYS = 680,
++	DISCONNECT = 681
  };
  
  #define is_identifier(x)	((x) >= FIRST_TOKEN &&	\
+-- 
+2.35.1
+
diff --git a/dhcp-paths.patch b/dhcp-paths.patch
index a4b0fef..7a7c38e 100644
--- a/dhcp-paths.patch
+++ b/dhcp-paths.patch
@@ -1,7 +1,28 @@
-diff -up dhcp-4.0.0/includes/dhcpd.h.paths dhcp-4.0.0/includes/dhcpd.h
---- dhcp-4.0.0/includes/dhcpd.h.paths	2008-01-01 15:09:21.000000000 -1000
-+++ dhcp-4.0.0/includes/dhcpd.h	2008-01-01 15:10:55.000000000 -1000
-@@ -1306,11 +1306,11 @@ typedef unsigned char option_mask [16];
+diff -urNpa dhcp-4.4.1.orig/doc/examples/dhclient-dhcpv6.conf dhcp-4.4.1/doc/examples/dhclient-dhcpv6.conf
+--- dhcp-4.4.1.orig/doc/examples/dhclient-dhcpv6.conf	2019-04-17 12:37:47.821000000 +0200
++++ dhcp-4.4.1/doc/examples/dhclient-dhcpv6.conf	2019-04-17 12:39:20.104000000 +0200
+@@ -8,4 +8,4 @@
+ also request dhcp6.sip-servers-addresses;
+ 
+ # Likely to be useful: the script path
+-script "/usr/local/etc/dhclient-script";
++script "/sbin/dhclient-script";
+diff -urNpa dhcp-4.4.1.orig/doc/examples/dhcpd-dhcpv6.conf dhcp-4.4.1/doc/examples/dhcpd-dhcpv6.conf
+--- dhcp-4.4.1.orig/doc/examples/dhcpd-dhcpv6.conf	2019-04-17 12:37:47.821000000 +0200
++++ dhcp-4.4.1/doc/examples/dhcpd-dhcpv6.conf	2019-04-17 12:39:20.104000000 +0200
+@@ -43,7 +43,7 @@ option dhcp6.domain-search "test.example
+ option dhcp6.info-refresh-time 21600;
+ 
+ # The path of the lease file
+-dhcpv6-lease-file-name "/usr/local/var/db/dhcpd6.leases";
++dhcpv6-lease-file-name "/var/lib/dhcpd/dhcpd6.leases";
+ 
+ # Static definition (must be global)
+ host myclient {
+diff -urNpa dhcp-4.4.1.orig/includes/dhcpd.h dhcp-4.4.1/includes/dhcpd.h
+--- dhcp-4.4.1.orig/includes/dhcpd.h	2019-04-17 12:37:47.829000000 +0200
++++ dhcp-4.4.1/includes/dhcpd.h	2019-04-17 12:39:20.105000000 +0200
+@@ -1549,11 +1549,11 @@ typedef unsigned char option_mask [16];
  #endif /* DEBUG */
  
  #ifndef _PATH_DHCPD_DB
@@ -15,17 +36,17 @@ diff -up dhcp-4.0.0/includes/dhcpd.h.paths dhcp-4.0.0/includes/dhcpd.h
  #endif
  
  #ifndef _PATH_DHCPD_PID
-@@ -1340,11 +1340,11 @@ typedef unsigned char option_mask [16];
+@@ -1583,11 +1583,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"/lib/dhclient/dhclient.leases"
++#define _PATH_DHCLIENT_DB	LOCALSTATEDIR"/lib/dhcpd/dhclient.leases"
  #endif
  
  #ifndef _PATH_DHCLIENT6_DB
 -#define _PATH_DHCLIENT6_DB	LOCALSTATEDIR"/db/dhclient6.leases"
-+#define _PATH_DHCLIENT6_DB	LOCALSTATEDIR"/lib/dhclient/dhclient6.leases"
++#define _PATH_DHCLIENT6_DB	LOCALSTATEDIR"/lib/dhcpd/dhclient6.leases"
  #endif
  
  #ifndef _PATH_RESOLV_CONF
diff --git a/dhcp-ppp.patch b/dhcp-ppp.patch
new file mode 100644
index 0000000..a5d03f4
--- /dev/null
+++ b/dhcp-ppp.patch
@@ -0,0 +1,175 @@
+From fe89d58ea8627c66feffa81997daa024834eeb15 Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:33:06 +0100
+Subject: [PATCH 13/28] DHCPv6 over PPP support (#626514)
+
+---
+ client/dhc6.c     |  3 ++-
+ client/dhclient.c | 17 ++++++++++++++---
+ common/bpf.c      | 16 ++++++++++++++++
+ common/lpf.c      | 16 ++++++++++++++++
+ includes/dhcp.h   |  2 ++
+ includes/dhcpd.h  |  2 +-
+ server/dhcpv6.c   |  3 +++
+ 7 files changed, 54 insertions(+), 5 deletions(-)
+
+diff --git a/client/dhc6.c b/client/dhc6.c
+index 35cf3d0..88fd07d 100644
+--- a/client/dhc6.c
++++ b/client/dhc6.c
+@@ -5737,7 +5737,8 @@ make_client6_options(struct client_state *client, struct option_state **op,
+ 	 */
+ 	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 --git a/client/dhclient.c b/client/dhclient.c
+index b49fcb3..a99e21f 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
+@@ -1223,8 +1223,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);
+ 		}
+ 	}
+ 
+@@ -4202,7 +4202,7 @@ write_options(struct client_state *client, struct option_state *options,
+  * 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;
+@@ -4215,6 +4215,15 @@ form_duid(struct data_string *duid, const char *file, int line)
+ 	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);
+@@ -4260,6 +4269,8 @@ form_duid(struct data_string *duid, const char *file, int line)
+ 		log_info("Created duid %s.", str);
+ 		dfree(str, MDL);
+ 	}
++	
++	return ISC_R_SUCCESS;
+ }
+ 
+ /* Write the default DUID to the lease store. */
+diff --git a/common/bpf.c b/common/bpf.c
+index d2a0549..aede242 100644
+--- a/common/bpf.c
++++ b/common/bpf.c
+@@ -650,6 +650,22 @@ get_hw_addr(const char *name, struct hardware *hw) {
+                         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 --git a/common/lpf.c b/common/lpf.c
+index bd20b3f..bb8822a 100644
+--- a/common/lpf.c
++++ b/common/lpf.c
+@@ -563,6 +563,22 @@ get_hw_addr(const char *name, struct hardware *hw) {
+ 			hw->hbuf[0] = HTYPE_FDDI;
+ 			memcpy(&hw->hbuf[1], sa->sa_data, 6);
+ 			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 --git a/includes/dhcp.h b/includes/dhcp.h
+index 5a73129..7202f1d 100644
+--- a/includes/dhcp.h
++++ b/includes/dhcp.h
+@@ -80,6 +80,8 @@ struct dhcp_packet {
+ 					 * is no standard for this so we
+ 					 * just steal a type            */
+ 
++#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 --git a/includes/dhcpd.h b/includes/dhcpd.h
+index 25e1c72..4c5e877 100644
+--- a/includes/dhcpd.h
++++ b/includes/dhcpd.h
+@@ -3071,7 +3071,7 @@ void client_dns_remove(struct client_state *client, struct iaddr *addr);
+ 
+ void dhcpv4_client_assignments(void);
+ void dhcpv6_client_assignments(void);
+-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 dhcp4o6_start(void);
+ 
+diff --git a/server/dhcpv6.c b/server/dhcpv6.c
+index 0ea0532..7d61dc5 100644
+--- a/server/dhcpv6.c
++++ b/server/dhcpv6.c
+@@ -482,6 +482,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;
+-- 
+2.35.1
+
diff --git a/dhcp-release-by-ifup.patch b/dhcp-release-by-ifup.patch
index 655c04f..c6e9376 100644
--- a/dhcp-release-by-ifup.patch
+++ b/dhcp-release-by-ifup.patch
@@ -1,13 +1,23 @@
-diff -urNp -x '*.orig' dhcp-4.3.5.org/client/dhclient.c dhcp-4.3.5/client/dhclient.c
---- dhcp-4.3.5.org/client/dhclient.c	2016-09-27 21:16:50.000000000 +0200
-+++ dhcp-4.3.5/client/dhclient.c	2021-04-01 22:09:11.002580226 +0200
-@@ -556,9 +556,81 @@ main(int argc, char **argv) {
+From be8f73c399c0f89192e57453db153aaa48fcbb2e Mon Sep 17 00:00:00 2001
+From: Pavel Zhukov <pzhukov at redhat.com>
+Date: Thu, 21 Feb 2019 10:21:14 +0100
+Subject: [PATCH 03/28] Handle releasing interfaces requested by /sbin/ifup
+
+---
+ client/dhclient.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 72 insertions(+)
+
+diff --git a/client/dhclient.c b/client/dhclient.c
+index 6c1c09a..07679a7 100644
+--- a/client/dhclient.c
++++ b/client/dhclient.c
+@@ -793,9 +793,81 @@ main(int argc, char **argv) {
  				}
  			}
  			fclose(pidfd);
 +		} else {
 +			/* handle release for interfaces requested with Red Hat
-+			 * /sbin/ifup - pidfile will be /var/run/dhclient-$interface.pid 
++			 * /sbin/ifup - pidfile will be /var/run/dhclient-$interface.pid
 +			 */
 +
 +			if ((path_dhclient_pid == NULL) || (*path_dhclient_pid == '\0'))
@@ -28,10 +38,10 @@ diff -urNp -x '*.orig' dhcp-4.3.5.org/client/dhclient.c dhcp-4.3.5/client/dhclie
 +
 +			for (dpfx=pfx; (dpfx >= 0) && (path_dhclient_pid[dpfx] != '-') && (path_dhclient_pid[dpfx] != '/'); dpfx--);
 +				if ((dpfx > -1) && (path_dhclient_pid[dpfx] != '/'))
-+					pfx = dpfx;                 
++					pfx = dpfx;
 +
 +			for (ip = interfaces; ip; ip = ip->next) {
-+				if (interfaces_requested && (ip->flags & (INTERFACE_REQUESTED)) && (ip->name != NULL)) {
++				if (interfaces_requested && (ip->flags & (INTERFACE_REQUESTED))) {
 +					int n_len = strlen(ip->name);
 +
 +					new_path_dhclient_pid = (char*) malloc(pfx + n_len + 6);
@@ -66,7 +76,7 @@ diff -urNp -x '*.orig' dhcp-4.3.5.org/client/dhclient.c dhcp-4.3.5/client/dhclie
 +		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);          
++				dhc_running = (access(procfn, F_OK) == 0);
<Skipped 638 lines>
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/dhcp.git/commitdiff/15c1a8319287edff43305ebc37c8b7fab896f48b




More information about the pld-cvs-commit mailing list