import dhcp-4.4.2-17.b1.el9

c9 imports/c9/dhcp-4.4.2-17.b1.el9
CentOS Sources 2 years ago committed by MSVSphere Packaging Team
commit 7fd4d04266

@ -0,0 +1 @@
e4338f80bd2118ba1578e4bd3c2c154ec9c12ce0 SOURCES/dhcp-4.4.2b1.tar.gz

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/dhcp-4.4.2b1.tar.gz

@ -0,0 +1,78 @@
From 23dfbc560028bf7429196db1a3826f8b80c19d3e Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:09:57 +0100
Subject: [PATCH 01/26] change bug url
Cc: pzhukov@redhat.com
---
omapip/errwarn.c | 47 ++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 42 insertions(+), 5 deletions(-)
diff --git a/omapip/errwarn.c b/omapip/errwarn.c
index e30f8a0..09a3004 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];
+// get BUG_REPORT_URL from /etc/os-release
+char * bug_report_url(void) {
+ FILE * file = fopen("/etc/os-release", "r");
+ size_t len;
+ char * line = NULL;
+ char * url = NULL;
+ size_t url_len = 256;
+
+ url = (char *) malloc(url_len * sizeof(char));
+ strcpy(url, "https://bugzilla.redhat.com/");
+
+ if (!file)
+ return url;
+
+ while ((getline(&line, &len, file)) != -1) {
+ if (strstr(line, "BUG_REPORT_URL") != NULL) {
+ char * start = strchr(line, '=');
+ char * rquotes = strrchr(line, '"');
+
+ if (rquotes != NULL) {
+ *rquotes = '\0';
+ strncpy(url, start+2, url_len);
+ } else {
+ strncpy(url, start+1, url_len);
+ }
+ url[url_len-1] = '\0';
+ fclose(file);
+ return url;
+ }
+ }
+ fclose(file);
+ return url;
+}
+
+
/* Log an error message, then exit... */
void log_fatal (const char * fmt, ... )
@@ -74,11 +109,13 @@ void log_fatal (const char * fmt, ... )
}
log_error ("%s", "");
- log_error ("If you think you have received this message due to a bug rather");
- log_error ("than a configuration issue please read the section on submitting");
- log_error ("bugs on either our web page at www.isc.org or in the README file");
- log_error ("before submitting a bug. These pages explain the proper");
- log_error ("process and the information we find helpful for debugging.");
+ log_error ("This version of ISC DHCP is based on the release available");
+ log_error ("on ftp.isc.org. Features have been added and other changes");
+ log_error ("have been made to the base software release in order to make");
+ log_error ("it work better with this distribution.");
+ log_error ("%s", "");
+ log_error ("Please report issues with this software via: ");
+ log_error ("%s", bug_report_url());
log_error ("%s", "");
log_error ("exiting.");
--
2.14.5

@ -0,0 +1,468 @@
From a26161b0fd45cdbeed3038ac63ff04e3b727248f Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:19:47 +0100
Subject: [PATCH 02/26] additional dhclient options
Cc: pzhukov@redhat.com
---
client/clparse.c | 10 +-
client/dhclient.8 | 27 ++++++
client/dhclient.c | 271 +++++++++++++++++++++++++++++++++++++++++++++++++++-
common/conflex.c | 2 +
includes/dhcpd.h | 3 +
includes/dhctoken.h | 1 +
6 files changed, 308 insertions(+), 6 deletions(-)
diff --git a/client/clparse.c b/client/clparse.c
index eaf48a8..7212e3a 100644
--- a/client/clparse.c
+++ b/client/clparse.c
@@ -189,6 +189,7 @@ isc_result_t read_client_conf ()
/* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
*/
top_level_config.requested_lease = 7200;
+ top_level_config.bootp_broadcast_always = 0;
group_allocate (&top_level_config.on_receipt, MDL);
if (!top_level_config.on_receipt)
@@ -394,7 +395,8 @@ void read_client_leases ()
interface-declaration |
LEASE client-lease-statement |
ALIAS client-lease-statement |
- KEY key-definition */
+ KEY key-definition |
+ BOOTP_BROADCAST_ALWAYS */
void parse_client_statement (cfile, ip, config)
struct parse *cfile;
@@ -817,6 +819,12 @@ void parse_client_statement (cfile, ip, config)
parse_lease_id_format(cfile);
break;
+ case BOOTP_BROADCAST_ALWAYS:
+ token = next_token(&val, (unsigned*)0, cfile);
+ config -> bootp_broadcast_always = 1;
+ parse_semi (cfile);
+ return;
+
default:
lose = 0;
diff --git a/client/dhclient.8 b/client/dhclient.8
index ebc750f..6d7fbdb 100644
--- a/client/dhclient.8
+++ b/client/dhclient.8
@@ -134,6 +134,33 @@ dhclient - Dynamic Host Configuration Protocol Client
.B -w
]
[
+.B -B
+]
+[
+.B -C
+.I dhcp-client-identifier
+]
+[
+.B -H
+.I host-name
+]
+[
+.B -F
+.I fqdn.fqdn
+]
+[
+.B -V
+.I vendor-class-identifier
+]
+[
+.B --request-options
+.I request-option-list
+]
+[
+.B --timeout
+.I timeout
+]
+[
.B --dad-wait-time
.I seconds
]
diff --git a/client/dhclient.c b/client/dhclient.c
index 825ab00..26a333c 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -41,6 +41,12 @@
#include <sys/wait.h>
#include <limits.h>
+/*
+ * Defined in stdio.h when _GNU_SOURCE is set, but we don't want to define
+ * that when building ISC code.
+ */
+extern int asprintf(char **strp, const char *fmt, ...);
+
TIME default_lease_time = 43200; /* 12 hours... */
TIME max_lease_time = 86400; /* 24 hours... */
@@ -110,6 +116,10 @@ char *mockup_relay = NULL;
char *progname = NULL;
+int bootp_broadcast_always = 0;
+
+extern struct option *default_requested_options[];
+
void run_stateless(int exit_mode, u_int16_t port);
static isc_result_t write_duid(struct data_string *duid);
@@ -183,8 +193,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}"
static void
@@ -243,6 +257,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;
+
+ int timeout_arg = 0;
+ char *arg_conf = NULL;
+ int arg_conf_len = 0;
+
/* Initialize client globals. */
memset(&default_duid, 0, sizeof(default_duid));
@@ -558,6 +582,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]);
+ exit(1);
+ }
+
+ if (strlen(argv[i]) >= DHCP_MAX_OPTION_LEN) {
+ log_error("-C option dhcp-client-identifier string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_MAX_OPTION_LEN-1);
+ exit(1);
+ }
+
+ dhcp_client_identifier_arg = argv[i];
+ } else if (!strcmp(argv[i], "-B")) {
+ bootp_broadcast_always = 1;
+ } else if (!strcmp(argv[i], "-H")) {
+ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
+ usage(use_noarg, argv[i-1]);
+ exit(1);
+ }
+
+ if (strlen(argv[i]) >= DHCP_MAX_OPTION_LEN) {
+ log_error("-H option host-name string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_MAX_OPTION_LEN-1);
+ exit(1);
+ }
+
+ if (dhcp_host_name_arg != NULL) {
+ log_error("The -H <host-name> and -F <fqdn> arguments are mutually exclusive");
+ exit(1);
+ }
+
+ dhcp_host_name_arg = argv[i];
+ } else if (!strcmp(argv[i], "-F")) {
+ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
+ usage(use_noarg, argv[i-1]);
+ exit(1);
+ }
+
+ if (strlen(argv[i]) >= DHCP_MAX_OPTION_LEN) {
+ log_error("-F option fqdn.fqdn string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_MAX_OPTION_LEN-1);
+ exit(1);
+ }
+
+ if (dhcp_fqdn_arg != NULL) {
+ log_error("Only one -F <fqdn> argument can be specified");
+ exit(1);
+ }
+
+ if (dhcp_host_name_arg != NULL) {
+ log_error("The -F <fqdn> and -H <host-name> arguments are mutually exclusive");
+ exit(1);
+ }
+
+ dhcp_fqdn_arg = argv[i];
+ } else if (!strcmp(argv[i], "--timeout")) {
+ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
+ usage(use_noarg, argv[i-1]);
+ exit(1);
+ }
+
+ if ((timeout_arg = atoi(argv[i])) <= 0) {
+ log_error("timeout option must be > 0 - bad value: %s",argv[i]);
+ exit(1);
+ }
+ } else if (!strcmp(argv[i], "-V")) {
+ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
+ usage(use_noarg, argv[i-1]);
+ exit(1);
+ }
+
+ if (strlen(argv[i]) >= DHCP_MAX_OPTION_LEN) {
+ log_error("-V option vendor-class-identifier string \"%s\" is too long - maximum length is: %d", argv[i], DHCP_MAX_OPTION_LEN-1);
+ exit(1);
+ }
+
+ dhcp_vendor_class_identifier_arg = argv[i];
+ } else if (!strcmp(argv[i], "--request-options")) {
+ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
+ usage(use_noarg, argv[i-1]);
+ exit(1);
+ }
+
+ dhclient_request_options = argv[i];
+
} else if (argv[i][0] == '-') {
usage("Unknown command: %s", argv[i]);
} else if (interfaces_requested < 0) {
@@ -754,6 +861,156 @@ main(int argc, char **argv) {
/* Parse the dhclient.conf file. */
read_client_conf();
+ /* Parse any extra command line configuration arguments: */
+ if ((dhcp_client_identifier_arg != NULL) && (*dhcp_client_identifier_arg != '\0')) {
+ arg_conf_len = asprintf(&arg_conf, "send dhcp-client-identifier \"%s\";", dhcp_client_identifier_arg);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to send -C option dhcp-client-identifier");
+ }
+
+ if ((dhcp_host_name_arg != NULL) && (*dhcp_host_name_arg != '\0')) {
+ if (arg_conf == 0) {
+ arg_conf_len = asprintf(&arg_conf, "send host-name \"%s\";", dhcp_host_name_arg);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to send -H option host-name");
+ } else {
+ char *last_arg_conf = arg_conf;
+ arg_conf = NULL;
+ arg_conf_len = asprintf(&arg_conf, "%s\nsend host-name \"%s\";", last_arg_conf, dhcp_host_name_arg);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to send -H option host-name");
+
+ free(last_arg_conf);
+ }
+ }
+
+ if ((dhcp_fqdn_arg != NULL) && (*dhcp_fqdn_arg != '\0')) {
+ if (arg_conf == 0) {
+ arg_conf_len = asprintf(&arg_conf, "send fqdn.fqdn \"%s\";", dhcp_fqdn_arg);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to send -F option fqdn.fqdn");
+ } else {
+ char *last_arg_conf = arg_conf;
+ arg_conf = NULL;
+ arg_conf_len = asprintf(&arg_conf, "%s\nsend fqdn.fqdn \"%s\";", last_arg_conf, dhcp_fqdn_arg);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to send -F option fqdn.fqdn");
+
+ free(last_arg_conf);
+ }
+ }
+
+ if (timeout_arg) {
+ if (arg_conf == 0) {
+ arg_conf_len = asprintf(&arg_conf, "timeout %d;", timeout_arg);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to process --timeout timeout argument");
+ } else {
+ char *last_arg_conf = arg_conf;
+ arg_conf = NULL;
+ arg_conf_len = asprintf(&arg_conf, "%s\ntimeout %d;", last_arg_conf, timeout_arg);
+
+ if ((arg_conf == 0) || (arg_conf_len == 0))
+ log_fatal("Unable to process --timeout timeout argument");
+
+ free(last_arg_conf);
+ }
+ }
+
+ if ((dhcp_vendor_class_identifier_arg != NULL) && (*dhcp_vendor_class_identifier_arg != '\0')) {
+ if (arg_conf == 0) {
+ arg_conf_len = asprintf(&arg_conf, "send vendor-class-identifier \"%s\";", dhcp_vendor_class_identifier_arg);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to send -V option vendor-class-identifier");
+ } else {
+ char *last_arg_conf = arg_conf;
+ arg_conf = NULL;
+ arg_conf_len = asprintf(&arg_conf, "%s\nsend vendor-class-identifier \"%s\";", last_arg_conf, dhcp_vendor_class_identifier_arg);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to send -V option vendor-class-identifier");
+
+ free(last_arg_conf);
+ }
+ }
+
+ if (dhclient_request_options != NULL) {
+ if (arg_conf == 0) {
+ arg_conf_len = asprintf(&arg_conf, "request %s;", dhclient_request_options);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to parse --request-options <request options list> argument");
+ } else {
+ char *last_arg_conf = arg_conf;
+ arg_conf = NULL;
+ arg_conf_len = asprintf(&arg_conf, "%s\nrequest %s;", last_arg_conf, dhclient_request_options);
+
+ if ((arg_conf == 0) || (arg_conf_len <= 0))
+ log_fatal("Unable to parse --request-options <request options list> argument");
+
+ free(last_arg_conf);
+ }
+ }
+
+ if (arg_conf) {
+ if (arg_conf_len == 0)
+ if ((arg_conf_len = strlen(arg_conf)) == 0)
+ /* huh ? cannot happen ! */
+ log_fatal("Unable to process -C/-H/-F/--timeout/-V/--request-options configuration arguments");
+
+ /* parse the extra dhclient.conf configuration arguments
+ * into top level config: */
+ struct parse *cfile = (struct parse *)0;
+ const char *val = NULL;
+ int token;
+
+ status = new_parse(&cfile, -1, arg_conf, arg_conf_len, "extra dhclient -C/-H/-F/--timeout/-V/--request-options configuration arguments", 0);
+
+ if ((status != ISC_R_SUCCESS) || (cfile -> warnings_occurred))
+ log_fatal("Cannot parse -C/-H/-F/--timeout/-V/--request-options configuration arguments !");
+ /* more detailed parse failures will be logged */
+
+ do {
+ token = peek_token(&val, (unsigned *)0, cfile);
+ if (token == END_OF_FILE)
+ break;
+
+ parse_client_statement(cfile, (struct interface_info *)0, &top_level_config);
+ } while (1);
+
+ if (cfile -> warnings_occurred)
+ log_fatal("Cannot parse -C/-H/-F/--timeout/-V/--request-options configuration arguments !");
+ end_parse(&cfile);
+
+ if (timeout_arg) {
+ /* we just set the toplevel timeout, but per-client
+ * timeouts may still be at defaults.
+ */
+ for (ip=interfaces; ip; ip = ip->next) {
+ if (ip->client->config->timeout == 60)
+ ip->client->config->timeout = timeout_arg;
+ }
+ }
+
+ if ((dhclient_request_options != 0) && (top_level_config.requested_options != default_requested_options)) {
+ for (ip=interfaces; ip; ip = ip->next) {
+ if (ip->client->config->requested_options == default_requested_options)
+ ip->client->config->requested_options = top_level_config.requested_options;
+ }
+ }
+
+ free(arg_conf);
+ arg_conf = NULL;
+ arg_conf_len = 0;
+ }
+
/* Parse the lease database. */
read_client_leases();
@@ -3226,7 +3483,8 @@ void make_discover (client, lease)
client -> packet.xid = random ();
client -> packet.secs = 0; /* filled in by send_discover. */
- if (can_receive_unicast_unconfigured (client -> interface))
+ if ((!(bootp_broadcast_always || client->config->bootp_broadcast_always))
+ && can_receive_unicast_unconfigured(client->interface))
client -> packet.flags = 0;
else
client -> packet.flags = htons (BOOTP_BROADCAST);
@@ -3311,7 +3569,9 @@ void make_request (client, lease)
} else {
memset (&client -> packet.ciaddr, 0,
sizeof client -> packet.ciaddr);
- if (can_receive_unicast_unconfigured (client -> interface))
+ if ((!(bootp_broadcast_always ||
+ client ->config->bootp_broadcast_always)) &&
+ can_receive_unicast_unconfigured (client -> interface))
client -> packet.flags = 0;
else
client -> packet.flags = htons (BOOTP_BROADCAST);
@@ -3374,7 +3634,8 @@ void make_decline (client, lease)
client -> packet.hops = 0;
client -> packet.xid = client -> xid;
client -> packet.secs = 0; /* Filled in by send_request. */
- if (can_receive_unicast_unconfigured (client -> interface))
+ if ((!(bootp_broadcast_always || client->config-> bootp_broadcast_always))
+ && can_receive_unicast_unconfigured (client->interface))
client -> packet.flags = 0;
else
client -> packet.flags = htons (BOOTP_BROADCAST);
diff --git a/common/conflex.c b/common/conflex.c
index 045b655..71c0bf5 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;
}
+ if (!strcasecmp (atom + 1, "ootp-broadcast-always"))
+ return BOOTP_BROADCAST_ALWAYS;
break;
case 'c':
if (!strcasecmp(atom + 1, "ase"))
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index 5930e6a..018fa34 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -1269,6 +1269,9 @@ struct client_config {
int lease_id_format; /* format for IDs in lease file,
TOKEN_OCTAL or TOKEN_HEX */
+
+ int bootp_broadcast_always; /* If nonzero, always set the BOOTP_BROADCAST
+ flag in requests */
};
/* Per-interface state used in the dhcp client... */
diff --git a/includes/dhctoken.h b/includes/dhctoken.h
index 5920f4f..7e7215a 100644
--- a/includes/dhctoken.h
+++ b/includes/dhctoken.h
@@ -377,6 +377,7 @@ enum dhcp_token {
TOKEN_HEX = 677,
TOKEN_OCTAL = 678,
KEY_ALGORITHM = 679
+ BOOTP_BROADCAST_ALWAYS = 680
};
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
--
2.14.5

@ -0,0 +1,99 @@
From af504e99abde04b881768d18eaa0054b36b16303 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:21:14 +0100
Subject: [PATCH 03/26] Handle releasing interfaces requested by /sbin/ifup
Cc: pzhukov@redhat.com
---
client/dhclient.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/client/dhclient.c b/client/dhclient.c
index 26a333c..2a2e9e6 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -787,9 +787,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
+ */
+
+ if ((path_dhclient_pid == NULL) || (*path_dhclient_pid == '\0'))
+ path_dhclient_pid = "/var/run/dhclient.pid";
+
+ char *new_path_dhclient_pid;
+ struct interface_info *ip;
+ int pdp_len = strlen(path_dhclient_pid), pfx, dpfx;
+
+ /* find append point: beginning of any trailing '.pid'
+ * or '-$IF.pid' */
+ for (pfx=pdp_len; (pfx >= 0) && (path_dhclient_pid[pfx] != '.') && (path_dhclient_pid[pfx] != '/'); pfx--);
+ if (pfx == -1)
+ pfx = pdp_len;
+
+ if (path_dhclient_pid[pfx] == '/')
+ pfx += 1;
+
+ for (dpfx=pfx; (dpfx >= 0) && (path_dhclient_pid[dpfx] != '-') && (path_dhclient_pid[dpfx] != '/'); dpfx--);
+ if ((dpfx > -1) && (path_dhclient_pid[dpfx] != '/'))
+ pfx = dpfx;
+
+ for (ip = interfaces; ip; ip = ip->next) {
+ if (interfaces_requested && (ip->flags & (INTERFACE_REQUESTED))) {
+ int n_len = strlen(ip->name);
+
+ new_path_dhclient_pid = (char*) malloc(pfx + n_len + 6);
+ strncpy(new_path_dhclient_pid, path_dhclient_pid, pfx);
+ sprintf(new_path_dhclient_pid + pfx, "-%s.pid", ip->name);
+
+ if ((pidfd = fopen(new_path_dhclient_pid, "r")) != NULL) {
+ e = fscanf(pidfd, "%ld\n", &temp);
+ oldpid = (pid_t)temp;
+
+ if (e != 0 && e != EOF) {
+ if (oldpid) {
+ if (kill(oldpid, SIGTERM) == 0)
+ unlink(path_dhclient_pid);
+ }
+ }
+
+ fclose(pidfd);
+ }
+
+ free(new_path_dhclient_pid);
+ }
+ }
+ }
+ } else {
+ FILE *pidfp = NULL;
+ long temp = 0;
+ pid_t dhcpid = 0;
+ int dhc_running = 0;
+ char procfn[256] = "";
+
+ if ((pidfp = fopen(path_dhclient_pid, "r")) != NULL) {
+ if ((fscanf(pidfp, "%ld", &temp)==1) && ((dhcpid=(pid_t)temp) > 0)) {
+ snprintf(procfn,256,"/proc/%u",dhcpid);
+ dhc_running = (access(procfn, F_OK) == 0);
+ }
+
+ fclose(pidfp);
+ }
+
+ if (dhc_running) {
+ log_fatal("dhclient(%u) is already running - exiting. ", dhcpid);
+ return(1);
}
}
+ write_client_pid_file();
+
if (!quiet) {
log_info("%s %s", message, PACKAGE_VERSION);
log_info(copyright);
--
2.14.5

@ -0,0 +1,118 @@
From 7e8cc8388ac31c5c2b1a423c6b2da0491b19f6f9 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:22:41 +0100
Subject: [PATCH 04/26] Support unicast BOOTP for IBM pSeries systems (and
maybe others)
Cc: pzhukov@redhat.com
---
server/bootp.c | 12 +++++++++++-
server/dhcp.c | 33 ++++++++++++++++++++++++++-------
2 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/server/bootp.c b/server/bootp.c
index 26a7607..2212f31 100644
--- a/server/bootp.c
+++ b/server/bootp.c
@@ -52,6 +52,7 @@ void bootp (packet)
char msgbuf [1024];
int ignorep;
int peer_has_leases = 0;
+ int norelay = 0;
if (packet -> raw -> op != BOOTREQUEST)
return;
@@ -67,7 +68,7 @@ void bootp (packet)
? inet_ntoa (packet -> raw -> giaddr)
: packet -> interface -> name);
- if (!locate_network (packet)) {
+ if ((norelay = locate_network (packet)) == 0) {
log_info ("%s: network unknown", msgbuf);
return;
}
@@ -428,6 +429,15 @@ void bootp (packet)
goto out;
}
+ } else if (norelay == 2) {
+ to.sin_addr = raw.ciaddr;
+ to.sin_port = remote_port;
+ if (fallback_interface) {
+ result = send_packet (fallback_interface, NULL, &raw,
+ outgoing.packet_length, from,
+ &to, &hto);
+ goto out;
+ }
/* If it comes from a client that already knows its address
and is not requesting a broadcast response, and we can
diff --git a/server/dhcp.c b/server/dhcp.c
index 6f3a91f..20f2a62 100644
--- a/server/dhcp.c
+++ b/server/dhcp.c
@@ -5224,6 +5224,7 @@ int locate_network (packet)
struct data_string data;
struct subnet *subnet = (struct subnet *)0;
struct option_cache *oc;
+ int norelay = 0;
#if defined(DHCPv6) && defined(DHCP4o6)
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
@@ -5245,12 +5246,24 @@ int locate_network (packet)
from the interface, if there is one. If not, fail. */
if (!oc && !packet -> raw -> giaddr.s_addr) {
if (packet -> interface -> shared_network) {
- shared_network_reference
- (&packet -> shared_network,
- packet -> interface -> shared_network, MDL);
- return 1;
+ struct in_addr any_addr;
+ any_addr.s_addr = INADDR_ANY;
+
+ if (!packet -> packet_type && memcmp(&packet -> raw -> ciaddr, &any_addr, 4)) {
+ struct iaddr cip;
+ memcpy(cip.iabuf, &packet -> raw -> ciaddr, 4);
+ cip.len = 4;
+ if (!find_grouped_subnet(&subnet, packet->interface->shared_network, cip, MDL))
+ norelay = 2;
+ }
+
+ if (!norelay) {
+ shared_network_reference(&packet -> shared_network, packet -> interface -> shared_network, MDL);
+ return 1;
+ }
+ } else {
+ return 0;
}
- return 0;
}
/* If there's an option indicating link connection, and it's valid,
@@ -5277,7 +5290,10 @@ int locate_network (packet)
data_string_forget (&data, MDL);
} else {
ia.len = 4;
- memcpy (ia.iabuf, &packet -> raw -> giaddr, 4);
+ if (norelay)
+ memcpy (ia.iabuf, &packet->raw->ciaddr, 4);
+ else
+ memcpy (ia.iabuf, &packet->raw->giaddr, 4);
}
/* If we know the subnet on which the IP address lives, use it. */
@@ -5285,7 +5301,10 @@ int locate_network (packet)
shared_network_reference (&packet -> shared_network,
subnet -> shared_network, MDL);
subnet_dereference (&subnet, MDL);
- return 1;
+ if (norelay)
+ return norelay;
+ else
+ return 1;
}
/* Otherwise, fail. */
--
2.14.5

@ -0,0 +1,60 @@
From a2a3554ff9e05d1a8e2c8aa843f1b6a33fce87e3 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:24:24 +0100
Subject: [PATCH 05/26] Change default requested options
Cc: pzhukov@redhat.com
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 7212e3a..39b95a0 100644
--- a/client/clparse.c
+++ b/client/clparse.c
@@ -31,7 +31,7 @@
struct client_config top_level_config;
-#define NUM_DEFAULT_REQUESTED_OPTS 9
+#define NUM_DEFAULT_REQUESTED_OPTS 14
/* 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 ()
option_code_hash_lookup(&default_requested_options[8],
dhcpv6_universe.code_hash, &code, 0, MDL);
+ /* 10 */
+ code = DHO_NIS_DOMAIN;
+ option_code_hash_lookup(&default_requested_options[9],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 11 */
+ code = DHO_NIS_SERVERS;
+ option_code_hash_lookup(&default_requested_options[10],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 12 */
+ code = DHO_NTP_SERVERS;
+ option_code_hash_lookup(&default_requested_options[11],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 13 */
+ code = DHO_INTERFACE_MTU;
+ option_code_hash_lookup(&default_requested_options[12],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
+ /* 14 */
+ code = DHO_DOMAIN_SEARCH;
+ option_code_hash_lookup(&default_requested_options[13],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
if (default_requested_options[code] == NULL)
log_fatal("Unable to find option definition for "
--
2.14.5

@ -0,0 +1,168 @@
From 846779467f7393b19e8d206405116e1e26e16efc Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:25:53 +0100
Subject: [PATCH 06/26] Various man-page-only fixes
Cc: pzhukov@redhat.com
---
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 3553afd..0db5516 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
-file.
+file, and to handle DHCP options not handled by default.
.PP
No standard client script exists for some operating systems, even though
the actual client may work, so a pioneering user may well need to create
@@ -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.
+.PP
+Immediately after dhclient brings an interface UP with a new IP address,
+subnet mask, and routes, in the REBOOT/BOUND states, it will check for the
+existence of an executable
+.B ETCDIR/dhclient-up-hooks
+script, and source it if found. This script can handle DHCP options in
+the environment that are not handled by default. A per-interface.
+.B ETCDIR/dhclient-${IF}-up-hooks
+script will override the generic script and be sourced when interface
+$IF has been brought up.
+.PP
+Immediately before dhclient brings an interface DOWN, removing its IP
+address, subnet mask, and routes, in the STOP/RELEASE states, it will
+check for the existence of an executable
+.B ETCDIR/dhclient-down-hooks
+script, and source it if found. This script can handle DHCP options in
+the environment that are not handled by default. A per-interface
+.B ETCDIR/dhclient-${IF}-down-hooks
+script will override the generic script and be sourced when interface
+$IF is about to be brought down.
.SH OPERATION
When dhclient needs to invoke the client configuration script, it
defines a set of variables in the environment, and then invokes
diff --git a/client/dhclient.conf.5 b/client/dhclient.conf.5
index fa3b908..566a881 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 33d4804..d9e1197 100644
--- a/common/dhcp-options.5
+++ b/common/dhcp-options.5
@@ -1068,6 +1068,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.
+.PP
+NOTE to Fedora dhclient users:
+.br
+dhclient-script interprets trailing 0 octets of the target as indicating
+the subnet class of the route, so for the following static-routes value:
+.br
+ option static-routes 172.0.0.0 172.16.2.254,
+.br
+ 192.168.0.0 192.168.2.254;
+.br
+dhclient-script will create routes:
+.br
+ 172/8 via 172.16.2.254 dev $interface
+.br
+ 192.168/16 via 192.168.2.254 dev $interface
.RE
.PP
.nf
diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5
index 17330d4..89b5540 100644
--- a/server/dhcpd.conf.5
+++ b/server/dhcpd.conf.5
@@ -527,6 +527,9 @@ pool {
};
.fi
.PP
+Dynamic BOOTP leases are not compatible with failover, and, as such,
+you need to disallow BOOTP in pools that you are using failover for.
+.PP
The server currently does very little sanity checking, so if you
configure it wrong, it will just fail in odd ways. I would recommend
therefore that you either do failover or don't do failover, but don't
@@ -541,9 +544,9 @@ primary server might look like this:
failover peer "foo" {
primary;
address anthrax.rc.example.com;
- port 519;
+ port 647;
peer address trantor.rc.example.com;
- peer port 520;
+ peer port 847;
max-response-delay 60;
max-unacked-updates 10;
mclt 3600;
@@ -1323,7 +1326,7 @@ the zone containing PTR records - for ISC BIND, something like this:
.PP
.nf
key DHCP_UPDATER {
- algorithm HMAC-MD5.SIG-ALG.REG.INT;
+ algorithm hmac-md5;
secret pRP5FapFoJ95JEL06sv4PQ==;
};
@@ -1346,7 +1349,7 @@ dhcpd.conf file:
.PP
.nf
key DHCP_UPDATER {
- algorithm HMAC-MD5.SIG-ALG.REG.INT;
+ algorithm hmac-md5;
secret pRP5FapFoJ95JEL06sv4PQ==;
};
@@ -2912,7 +2915,8 @@ statement
The \fInext-server\fR statement is used to specify the host address of
the server from which the initial boot file (specified in the
\fIfilename\fR statement) is to be loaded. \fIServer-name\fR should
-be a numeric IP address or a domain name.
+be a numeric IP address or a domain name. If no \fInext-server\fR statement
+applies to a given client, the address 0.0.0.0 is used.
.RE
.PP
The
--
2.14.5

@ -0,0 +1,54 @@
From ac65289663532db0bc1de449ca2a0eb4c8c2ca6f Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:26:34 +0100
Subject: [PATCH 07/26] Change paths to conform to our standards
Cc: pzhukov@redhat.com
---
doc/examples/dhcpd-dhcpv6.conf | 2 +-
includes/dhcpd.h | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/doc/examples/dhcpd-dhcpv6.conf b/doc/examples/dhcpd-dhcpv6.conf
index 448a6a6..2357824 100644
--- a/doc/examples/dhcpd-dhcpv6.conf
+++ b/doc/examples/dhcpd-dhcpv6.conf
@@ -43,7 +43,7 @@ option dhcp6.domain-search "test.example.com","example.com";
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 --git a/includes/dhcpd.h b/includes/dhcpd.h
index 018fa34..3632a6b 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -1545,7 +1545,7 @@ typedef unsigned char option_mask [16];
#else /* !DEBUG */
#ifndef _PATH_DHCPD_CONF
-#define _PATH_DHCPD_CONF "/etc/dhcpd.conf"
+#define _PATH_DHCPD_CONF "/etc/dhcp/dhcpd.conf"
#endif /* DEBUG */
#ifndef _PATH_DHCPD_DB
@@ -1567,11 +1567,11 @@ typedef unsigned char option_mask [16];
#endif /* DEBUG */
#ifndef _PATH_DHCLIENT_CONF
-#define _PATH_DHCLIENT_CONF "/etc/dhclient.conf"
+#define _PATH_DHCLIENT_CONF "/etc/dhcp/dhclient.conf"
#endif
#ifndef _PATH_DHCLIENT_SCRIPT
-#define _PATH_DHCLIENT_SCRIPT "/sbin/dhclient-script"
+#define _PATH_DHCLIENT_SCRIPT "/usr/sbin/dhclient-script"
#endif
#ifndef _PATH_DHCLIENT_PID
--
2.14.5

@ -0,0 +1,367 @@
From d2da34706f140101c34f6a9806c258411806a939 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:27:18 +0100
Subject: [PATCH 08/26] Make sure all open file descriptors are closed-on-exec
for SELinux
Cc: pzhukov@redhat.com
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 39b95a0..44387ed 100644
--- a/client/clparse.c
+++ b/client/clparse.c
@@ -288,7 +288,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;
@@ -364,7 +364,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 2a2e9e6..a86ab9e 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -273,11 +273,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)
@@ -765,7 +765,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;
@@ -820,7 +820,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;
@@ -845,7 +845,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);
@@ -3808,7 +3808,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;
@@ -4003,7 +4003,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;
@@ -4207,7 +4207,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;
@@ -4786,9 +4786,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 ();
@@ -4806,14 +4806,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 16076fe..67b6d64 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 3990bf1..a941258 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 d822c15..a9132bc 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 a01f520..b209e3f 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 9785879..e0a524f 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 45bd508..5ea7486 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 d8caaaf..ea1be18 100644
--- a/relay/dhcrelay.c
+++ b/relay/dhcrelay.c
@@ -296,11 +296,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)
@@ -776,13 +776,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 d2cedfe..2743979 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 67e6cc1..6181528 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 55ffae7..530a923 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 5126d24..555545c 100644
--- a/server/ldap.c
+++ b/server/ldap.c
@@ -1446,7 +1446,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.14.5

@ -0,0 +1,27 @@
From a0a2186ce52a31357d4eb3c32d7d6887e4603814 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:28:13 +0100
Subject: [PATCH 09/26] Fix 'garbage in format string' error
Cc: pzhukov@redhat.com
RHBZ: 450042
---
common/tables.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/common/tables.c b/common/tables.c
index c1aa214..d2294c0 100644
--- a/common/tables.c
+++ b/common/tables.c
@@ -215,7 +215,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.14.5

@ -0,0 +1,32 @@
From ed7610cdb2e8ebdbaee618e477879e7e008d4f29 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:29:08 +0100
Subject: [PATCH 10/26] Handle null timeout
Cc: pzhukov@redhat.com
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 0207ad3..d7fe200 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.14.5

@ -0,0 +1,278 @@
From 3b37f4b7bb3a17f8bd655be919915a1912062ea6 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:30:28 +0100
Subject: [PATCH 11/26] Drop unnecessary capabilities
Cc: pzhukov@redhat.com
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 --git a/client/Makefile.am b/client/Makefile.am
index d177159..0689185 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -17,6 +17,7 @@ dhclient_LDADD = ../common/libdhcp.@A@ ../omapip/libomapi.@A@ \
@BINDLIBIRSDIR@/libirs.@A@ \
@BINDLIBDNSDIR@/libdns.@A@ \
@BINDLIBISCCFGDIR@/libisccfg.@A@ \
- @BINDLIBISCDIR@/libisc.@A@
+ @BINDLIBISCDIR@/libisc.@A@ \
+ $(CAPNG_LDADD)
man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
EXTRA_DIST = $(man_MANS)
diff --git a/client/dhclient-script.8 b/client/dhclient-script.8
index 0db5516..2eddb8f 100644
--- a/client/dhclient-script.8
+++ b/client/dhclient-script.8
@@ -243,6 +243,16 @@ repeatedly initialized to the values provided by one server, and then
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 --git a/client/dhclient.8 b/client/dhclient.8
index 6d7fbdb..0145b9f 100644
--- a/client/dhclient.8
+++ b/client/dhclient.8
@@ -134,6 +134,9 @@ dhclient - Dynamic Host Configuration Protocol Client
.B -w
]
[
+.B -nc
+]
+[
.B -B
]
[
@@ -328,6 +331,32 @@ not to exit when it doesn't find any such interfaces. The
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 \-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
diff --git a/client/dhclient.c b/client/dhclient.c
index a86ab9e..5d3f5bc 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -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.
@@ -266,6 +270,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));
@@ -665,6 +672,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) {
@@ -725,6 +736,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 --git a/configure.ac b/configure.ac
index a797438..15fc0d7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -612,6 +612,41 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[void foo() __attribute__((noreturn));
# 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 --git a/relay/Makefile.am b/relay/Makefile.am
index 2ba5979..8900e0b 100644
--- a/relay/Makefile.am
+++ b/relay/Makefile.am
@@ -6,7 +6,8 @@ dhcrelay_LDADD = ../common/libdhcp.@A@ ../omapip/libomapi.@A@ \
@BINDLIBIRSDIR@/libirs.@A@ \
@BINDLIBDNSDIR@/libdns.@A@ \
@BINDLIBISCCFGDIR@/libisccfg.@A@ \
- @BINDLIBISCDIR@/libisc.@A@
+ @BINDLIBISCDIR@/libisc.@A@ \
+ $(CAPNG_LDADD)
man_MANS = dhcrelay.8
EXTRA_DIST = $(man_MANS)
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
index ea1be18..7b4f4f1 100644
--- a/relay/dhcrelay.c
+++ b/relay/dhcrelay.c
@@ -32,6 +32,11 @@
#include <sys/time.h>
#include <isc/file.h>
+#ifdef HAVE_LIBCAP_NG
+# include <cap-ng.h>
+ int keep_capabilities = 0;
+#endif
+
TIME default_lease_time = 43200; /* 12 hours... */
TIME max_lease_time = 86400; /* 24 hours... */
struct tree_cache *global_options[256];
@@ -590,6 +595,10 @@ main(int argc, char **argv) {
if (++i == argc)
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)
@@ -660,6 +669,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);
@@ -816,6 +836,15 @@ main(int argc, char **argv) {
signal(SIGTERM, dhcp_signal_handler); /* kill */
#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();
--
2.14.5

@ -0,0 +1,439 @@
From 01b1dcfef129a4eccfaf0f63a216774019f82dca Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:32:35 +0100
Subject: [PATCH 12/26] RFC 3442 - Classless Static Route Option for DHCPv4
(#516325)
Cc: pzhukov@redhat.com
(Submitted to dhcp-bugs@isc.org - [ISC-Bugs #24572])
---
client/clparse.c | 13 ++++++++++--
common/dhcp-options.5 | 43 +++++++++++++++++++++++++++++++++++++++
common/inet.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++
common/options.c | 49 +++++++++++++++++++++++++++++++++++++++++++-
common/parse.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++-
common/tables.c | 2 ++
includes/dhcp.h | 1 +
includes/dhcpd.h | 2 ++
includes/dhctoken.h | 5 +++--
9 files changed, 219 insertions(+), 6 deletions(-)
diff --git a/client/clparse.c b/client/clparse.c
index 44387ed..862e4f9 100644
--- a/client/clparse.c
+++ b/client/clparse.c
@@ -31,7 +31,7 @@
struct client_config top_level_config;
-#define NUM_DEFAULT_REQUESTED_OPTS 14
+#define NUM_DEFAULT_REQUESTED_OPTS 15
/* There can be 2 extra requested options for DHCPv4-over-DHCPv6. */
struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 2 + 1];
@@ -87,7 +87,11 @@ isc_result_t read_client_conf ()
dhcp_universe.code_hash, &code, 0, MDL);
/* 4 */
- code = DHO_ROUTERS;
+ /* The Classless Static Routes option code MUST appear in the parameter
+ * request list prior to both the Router option code and the Static
+ * Routes option code, if present. (RFC3442)
+ */
+ code = DHO_CLASSLESS_STATIC_ROUTES;
option_code_hash_lookup(&default_requested_options[3],
dhcp_universe.code_hash, &code, 0, MDL);
@@ -141,6 +145,11 @@ isc_result_t read_client_conf ()
option_code_hash_lookup(&default_requested_options[13],
dhcp_universe.code_hash, &code, 0, MDL);
+ /* 15 */
+ code = DHO_ROUTERS;
+ option_code_hash_lookup(&default_requested_options[14],
+ dhcp_universe.code_hash, &code, 0, MDL);
+
for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
if (default_requested_options[code] == NULL)
log_fatal("Unable to find option definition for "
diff --git a/common/dhcp-options.5 b/common/dhcp-options.5
index d9e1197..2343b19 100644
--- a/common/dhcp-options.5
+++ b/common/dhcp-options.5
@@ -110,6 +110,26 @@ hexadecimal, separated by colons. For example:
or
option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f;
.fi
+.PP
+The
+.B destination-descriptor
+describe the IP subnet number and subnet mask
+of a particular destination using a compact encoding. This encoding
+consists of one octet describing the width of the subnet mask,
+followed by all the significant octets of the subnet number.
+The following table contains some examples of how various subnet
+number/mask combinations can be encoded:
+.nf
+.sp 1
+Subnet number Subnet mask Destination descriptor
+0 0 0
+10.0.0.0 255.0.0.0 8.10
+10.0.0.0 255.255.255.0 24.10.0.0
+10.17.0.0 255.255.0.0 16.10.17
+10.27.129.0 255.255.255.0 24.10.27.129
+10.229.0.128 255.255.255.128 25.10.229.0.128
+10.198.122.47 255.255.255.255 32.10.198.122.47
+.fi
.SH SETTING OPTION VALUES USING EXPRESSIONS
Sometimes it's helpful to be able to set the value of a DHCP option
based on some value that the client has sent. To do this, you can
@@ -1086,6 +1106,29 @@ dhclient-script will create routes:
.RE
.PP
.nf
+.B option \fBclassless-static-routes\fR \fIdestination-descriptor ip-address\fR
+ [\fB,\fR \fIdestination-descriptor ip-address\fR...]\fB;\fR
+.fi
+.RS 0.25i
+.PP
+This option (see RFC3442) specifies a list of classless static routes
+that the client should install in its routing cache.
+.PP
+This option can contain one or more static routes, each of which
+consists of a destination descriptor and the IP address of the router
+that should be used to reach that destination.
+.PP
+Many clients may not implement the Classless Static Routes option.
+DHCP server administrators should therefore configure their DHCP
+servers to send both a Router option and a Classless Static Routes
+option, and should specify the default router(s) both in the Router
+option and in the Classless Static Routes option.
+.PP
+If the DHCP server returns both a Classless Static Routes option and
+a Router option, the DHCP client ignores the Router option.
+.RE
+.PP
+.nf
.B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR
[\fB,\fR \fIip-address\fR...]\fB;\fR
.fi
diff --git a/common/inet.c b/common/inet.c
index c4da73c..981fb92 100644
--- a/common/inet.c
+++ b/common/inet.c
@@ -519,6 +519,60 @@ free_iaddrcidrnetlist(struct iaddrcidrnetlist **result) {
return ISC_R_SUCCESS;
}
+static const char *
+inet_ntopdd(const unsigned char *src, unsigned srclen, char *dst, size_t size)
+{
+ char tmp[sizeof("32.255.255.255.255")];
+ int len;
+
+ switch (srclen) {
+ case 2:
+ len = sprintf (tmp, "%u.%u", src[0], src[1]);
+ break;
+ case 3:
+ len = sprintf (tmp, "%u.%u.%u", src[0], src[1], src[2]);
+ break;
+ case 4:
+ len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
+ break;
+ case 5:
+ len = sprintf (tmp, "%u.%u.%u.%u.%u", src[0], src[1], src[2], src[3], src[4]);
+ break;
+ default:
+ return NULL;
+ }
+ if (len < 0)
+ return NULL;
+
+ if (len > size) {
+ errno = ENOSPC;
+ return NULL;
+ }
+
+ return strcpy (dst, tmp);
+}
+
+/* pdestdesc() turns an iaddr structure into a printable dest. descriptor */
+const char *
+pdestdesc(const struct iaddr addr) {
+ static char pbuf[sizeof("255.255.255.255.255")];
+
+ if (addr.len == 0) {
+ return "<null destination descriptor>";
+ }
+ if (addr.len == 1) {
+ return "0";
+ }
+ if ((addr.len >= 2) && (addr.len <= 5)) {
+ return inet_ntopdd(addr.iabuf, addr.len, pbuf, sizeof(pbuf));
+ }
+
+ log_fatal("pdestdesc():%s:%d: Invalid destination descriptor length %d.",
+ MDL, addr.len);
+ /* quell compiler warnings */
+ return NULL;
+}
+
/* piaddr() turns an iaddr structure into a printable address. */
/* XXX: should use a const pointer rather than passing the structure */
const char *
diff --git a/common/options.c b/common/options.c
index fc0e088..3034cf0 100644
--- a/common/options.c
+++ b/common/options.c
@@ -729,7 +729,11 @@ cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
* packet.
*/
priority_list[priority_len++] = DHO_SUBNET_MASK;
- priority_list[priority_len++] = DHO_ROUTERS;
+ if (lookup_option(&dhcp_universe, cfg_options,
+ DHO_CLASSLESS_STATIC_ROUTES))
+ priority_list[priority_len++] = DHO_CLASSLESS_STATIC_ROUTES;
+ else
+ priority_list[priority_len++] = DHO_ROUTERS;
priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS;
priority_list[priority_len++] = DHO_HOST_NAME;
priority_list[priority_len++] = DHO_FQDN;
@@ -1804,6 +1808,7 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
unsigned long tval;
isc_boolean_t a_array = ISC_FALSE;
int len_used;
+ unsigned int octets = 0;
if (emit_commas)
comma = ',';
@@ -1812,6 +1817,7 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
memset (enumbuf, 0, sizeof enumbuf);
+ if (option->format[0] != 'R') { /* see explanation lower */
/* Figure out the size of the data. */
for (l = i = 0; option -> format [i]; i++, l++) {
if (l >= sizeof(fmtbuf) - 1)
@@ -2004,6 +2010,33 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
if (numhunk < 0)
numhunk = 1;
+ } else { /* option->format[i] == 'R') */
+ /* R (destination descriptor) has variable length.
+ * We can find it only in classless static route option,
+ * so we are for sure parsing classless static route option now.
+ * We go through whole the option to check whether there are no
+ * missing/extra bytes.
+ * I didn't find out how to improve the existing code and that's the
+ * reason for this separate 'else' where I do my own checkings.
+ * I know it's little bit unsystematic, but it works.
+ */
+ numhunk = 0;
+ numelem = 2; /* RI */
+ fmtbuf[0]='R'; fmtbuf[1]='I'; fmtbuf[2]=0;
+ for (i =0; i < len; i = i + octets + 5) {
+ if (data[i] > 32) { /* subnet mask width */
+ log_error ("wrong subnet mask width in destination descriptor");
+ break;
+ }
+ numhunk++;
+ octets = ((data[i]+7) / 8);
+ }
+ if (i != len) {
+ log_error ("classless static routes option has wrong size or "
+ "there's some garbage in format");
+ }
+ }
+
/* Cycle through the array (or hunk) printing the data. */
for (i = 0; i < numhunk; i++) {
if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) {
@@ -2159,6 +2192,20 @@ const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
strcpy(op, piaddr(iaddr));
dp += 4;
break;
+
+ case 'R':
+ if (dp[0] <= 32)
+ iaddr.len = (((dp[0]+7)/8)+1);
+ else {
+ log_error ("wrong subnet mask width in destination descriptor");
+ return "<error>";
+ }
+
+ memcpy(iaddr.iabuf, dp, iaddr.len);
+ strcpy(op, pdestdesc(iaddr));
+ dp += iaddr.len;
+ break;
+
case '6':
iaddr.len = 16;
memcpy(iaddr.iabuf, dp, 16);
diff --git a/common/parse.c b/common/parse.c
index 3ac4ebf..f17bc0b 100644
--- a/common/parse.c
+++ b/common/parse.c
@@ -344,6 +344,39 @@ int parse_ip_addr (cfile, addr)
return 0;
}
+/*
+ * destination-descriptor :== NUMBER DOT NUMBER |
+ * NUMBER DOT NUMBER DOT NUMBER |
+ * NUMBER DOT NUMBER DOT NUMBER DOT NUMBER |
+ * NUMBER DOT NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
+ */
+
+int parse_destination_descriptor (cfile, addr)
+ struct parse *cfile;
+ struct iaddr *addr;
+{
+ unsigned int mask_width, dest_dest_len;
+ addr -> len = 0;
+ if (parse_numeric_aggregate (cfile, addr -> iabuf,
+ &addr -> len, DOT, 10, 8)) {
+ mask_width = (unsigned int)addr->iabuf[0];
+ dest_dest_len = (((mask_width+7)/8)+1);
+ if (mask_width > 32) {
+ parse_warn (cfile,
+ "subnet mask width (%u) greater than 32.", mask_width);
+ }
+ else if (dest_dest_len != addr->len) {
+ parse_warn (cfile,
+ "destination descriptor with subnet mask width %u "
+ "should have %u octets, but has %u octets.",
+ mask_width, dest_dest_len, addr->len);
+ }
+
+ return 1;
+ }
+ return 0;
+}
+
/*
* Return true if every character in the string is hexadecimal.
*/
@@ -724,8 +757,10 @@ unsigned char *parse_numeric_aggregate (cfile, buf,
if (count) {
token = peek_token (&val, (unsigned *)0, cfile);
if (token != separator) {
- if (!*max)
+ if (!*max) {
+ *max = count;
break;
+ }
if (token != RBRACE && token != LBRACE)
token = next_token (&val,
(unsigned *)0,
@@ -1672,6 +1707,9 @@ int parse_option_code_definition (cfile, option)
case IP_ADDRESS:
type = 'I';
break;
+ case DESTINATION_DESCRIPTOR:
+ type = 'R';
+ break;
case IP6_ADDRESS:
type = '6';
break;
@@ -5101,6 +5139,15 @@ int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
}
break;
+ case 'R': /* destination descriptor */
+ if (!parse_destination_descriptor (cfile, &addr)) {
+ return 0;
+ }
+ if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1, MDL)) {
+ return 0;
+ }
+ break;
+
case '6': /* IPv6 address. */
if (!parse_ip6_addr(cfile, &addr)) {
return 0;
@@ -5378,6 +5425,13 @@ int parse_option_decl (oc, cfile)
goto exit;
len = ip_addr.len;
dp = ip_addr.iabuf;
+ goto alloc;
+
+ case 'R': /* destination descriptor */
+ if (!parse_destination_descriptor (cfile, &ip_addr))
+ goto exit;
+ len = ip_addr.len;
+ dp = ip_addr.iabuf;
alloc:
if (hunkix + len > sizeof hunkbuf) {
diff --git a/common/tables.c b/common/tables.c
index d2294c0..f1be07d 100644
--- a/common/tables.c
+++ b/common/tables.c
@@ -45,6 +45,7 @@ HASH_FUNCTIONS (option_code, const unsigned *, struct option,
Format codes:
I - IPv4 address
+ R - destination descriptor (RFC3442)
6 - IPv6 address
l - 32-bit signed integer
L - 32-bit unsigned integer
@@ -216,6 +217,7 @@ static struct option dhcp_options[] = {
#endif
{ "subnet-selection", "I", &dhcp_universe, 118, 1 },
{ "domain-search", "D", &dhcp_universe, 119, 1 },
+ { "classless-static-routes", "RIA", &dhcp_universe, 121, 1 },
{ "vivco", "Evendor-class.", &dhcp_universe, 124, 1 },
{ "vivso", "Evendor.", &dhcp_universe, 125, 1 },
#if 0
diff --git a/includes/dhcp.h b/includes/dhcp.h
index 0a74137..95bf539 100644
--- a/includes/dhcp.h
+++ b/includes/dhcp.h
@@ -158,6 +158,7 @@ struct dhcp_packet {
#define DHO_ASSOCIATED_IP 92
#define DHO_SUBNET_SELECTION 118 /* RFC3011! */
#define DHO_DOMAIN_SEARCH 119 /* RFC3397 */
+#define DHO_CLASSLESS_STATIC_ROUTES 121 /* RFC3442 */
#define DHO_VIVCO_SUBOPTIONS 124
#define DHO_VIVSO_SUBOPTIONS 125
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index 3632a6b..2ac39ae 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -2951,6 +2951,7 @@ isc_result_t range2cidr(struct iaddrcidrnetlist **result,
const struct iaddr *lo, const struct iaddr *hi);
isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result);
const char *piaddr (struct iaddr);
+const char *pdestdesc (struct iaddr);
char *piaddrmask(struct iaddr *, struct iaddr *);
char *piaddrcidr(const struct iaddr *, unsigned int);
u_int16_t validate_port(char *);
@@ -3169,6 +3170,7 @@ void parse_client_lease_declaration (struct parse *,
int parse_option_decl (struct option_cache **, struct parse *);
void parse_string_list (struct parse *, struct string_list **, int);
int parse_ip_addr (struct parse *, struct iaddr *);
+int parse_destination_descriptor (struct parse *, struct iaddr *);
int parse_ip_addr_with_subnet(struct parse *, struct iaddrmatch *);
void parse_reject_statement (struct parse *, struct client_config *);
diff --git a/includes/dhctoken.h b/includes/dhctoken.h
index 7e7215a..b4d93ba 100644
--- a/includes/dhctoken.h
+++ b/includes/dhctoken.h
@@ -376,8 +376,9 @@ enum dhcp_token {
LEASE_ID_FORMAT = 676,
TOKEN_HEX = 677,
TOKEN_OCTAL = 678,
- KEY_ALGORITHM = 679
- BOOTP_BROADCAST_ALWAYS = 680
+ KEY_ALGORITHM = 679,
+ BOOTP_BROADCAST_ALWAYS = 680,
+ DESTINATION_DESCRIPTOR = 681
};
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
--
2.14.5

@ -0,0 +1,176 @@
From 234747fbfd6c6429619ba843713d5b39fb4a513d Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:33:06 +0100
Subject: [PATCH 13/26] DHCPv6 over PPP support (#626514)
Cc: pzhukov@redhat.com
---
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 16a0838..3171828 100644
--- a/client/dhc6.c
+++ b/client/dhc6.c
@@ -5744,7 +5744,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 5d3f5bc..301132c 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -1202,8 +1202,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);
}
}
@@ -3956,7 +3956,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;
@@ -3969,6 +3969,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);
@@ -4014,6 +4023,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 67b6d64..ffbd09a 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 82a279b..b0ed01c 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 95bf539..4cc547a 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 2ac39ae..faa9251 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -3051,7 +3051,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 a7110f9..c5ce7e8 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.14.5

@ -0,0 +1,629 @@
From 042082b4410f158ec86ca8478689b34bc12518e6 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:34:21 +0100
Subject: [PATCH 14/27] IPoIB support (#660681)
Cc: pzhukov@redhat.com
(Submitted to dhcp-bugs@isc.org - [ISC-Bugs #24249])
---
client/dhclient.c | 32 ++++++
common/bpf.c | 32 ++++++
common/discover.c | 4 +-
common/lpf.c | 276 ++++++++++++++++++++++++++++++++++++++++++----
common/socket.c | 8 +-
includes/dhcpd.h | 6 +-
6 files changed, 329 insertions(+), 29 deletions(-)
diff --git a/client/dhclient.c b/client/dhclient.c
index 301132c..dc9080e 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -205,6 +205,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)
{
@@ -1191,6 +1193,13 @@ main(int argc, char **argv) {
}
srandom(seed + cur_time + (unsigned)getpid());
+ /* Setup specific Infiniband options */
+ for (ip = interfaces; ip; ip = ip->next) {
+ if (ip->client &&
+ (ip->hw_address.hbuf[0] == HTYPE_INFINIBAND)) {
+ setup_ib_interface(ip);
+ }
+ }
/*
* Establish a default DUID. We always do so for v6 and
@@ -1486,6 +1495,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 ffbd09a..568e3d9 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 6ef8852..65881fc 100644
--- a/common/discover.c
+++ b/common/discover.c
@@ -894,7 +894,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
@@ -907,7 +907,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 b0ed01c..a9e19f4 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);
@@ -539,16 +691,61 @@ get_hw_addr(const char *name, struct hardware *hw) {
memset(&tmp, 0, sizeof(tmp));
strcpy(tmp.ifr_name, name);
if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) {
- log_fatal("Error getting hardware address for \"%s\": %m",
+ 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 483eb9c..6e1caac 100644
--- a/common/socket.c
+++ b/common/socket.c
@@ -350,7 +350,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. */
@@ -413,7 +413,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",
@@ -567,7 +567,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) {
@@ -623,7 +623,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 faa9251..0c1a0aa 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];
@@ -1365,6 +1368,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.
*/
@@ -2633,7 +2637,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.26.2

@ -0,0 +1,332 @@
From 3d3e442ed1316930a5360e4d5a56b46a42a29419 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:35:47 +0100
Subject: [PATCH 15/26] Add GUID/DUID to dhcpd logs (#1064416)
Cc: pzhukov@redhat.com
---
client/dhclient.c | 75 ++++++++++++++++++++++++++++++++++++++++++----------
server/dhcp.c | 78 +++++++++++++++++++++++++++++++++----------------------
2 files changed, 108 insertions(+), 45 deletions(-)
diff --git a/client/dhclient.c b/client/dhclient.c
index dc9080e..8e57da9 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -1170,6 +1170,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
@@ -1184,14 +1204,36 @@ main(int argc, char **argv) {
Not much entropy, but we're booting, so we're not likely to
find anything better. */
seed = 0;
+ int seed_flag = 0;
for (ip = interfaces; ip; ip = ip->next) {
int junk;
+ if ( ip -> hw_address.hlen <= sizeof seed )
+ continue;
memcpy(&junk,
&ip->hw_address.hbuf[ip->hw_address.hlen -
sizeof seed], sizeof seed);
seed += junk;
+ seed_flag = 1;
}
- srandom(seed + cur_time + (unsigned)getpid());
+ if ( seed_flag == 0 ) {
+ if ( backup_seed != 0 ) {
+ seed = backup_seed;
+ log_info ("xid: rand init seed (0x%x) built using all"
+ " available interfaces",seed);
+ }
+ else {
+ seed = cur_time^((unsigned) gethostid()) ;
+ log_info ("xid: warning: no netdev with useable HWADDR found"
+ " for seed's uniqueness enforcement");
+ log_info ("xid: rand init seed (0x%x) built using gethostid",
+ seed);
+ }
+ /* we only use seed and no current time as a broadcast reply */
+ /* will certainly be used by the hwaddrless interface */
+ srandom(seed + ((unsigned)(cur_tv.tv_usec * 1000000)) + (unsigned)getpid());
+ }
+ else
+ srandom(seed + ((unsigned)(cur_tv.tv_usec * 1000000)) + (unsigned)getpid());
/* Setup specific Infiniband options */
for (ip = interfaces; ip; ip = ip->next) {
@@ -1746,10 +1788,10 @@ void dhcpack (packet)
#endif
return;
}
-
- log_info ("DHCPACK of %s from %s",
- inet_ntoa(packet->raw->yiaddr),
- piaddr (packet->client_addr));
+ log_info ("DHCPACK of %s from %s (xid=0x%x)",
+ inet_ntoa(packet->raw->yiaddr),
+ piaddr (packet -> client_addr),
+ ntohl(client -> xid));
lease = packet_to_lease (packet, client);
if (!lease) {
@@ -2669,7 +2711,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)
@@ -2802,10 +2844,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)
@@ -3108,10 +3150,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) {
@@ -3168,11 +3212,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)
@@ -3231,11 +3277,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 20f2a62..0582c4c 100644
--- a/server/dhcp.c
+++ b/server/dhcp.c
@@ -87,6 +87,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;
@@ -129,9 +165,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)
@@ -328,9 +362,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>")),
@@ -542,9 +574,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>")),
@@ -785,9 +815,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,
@@ -879,9 +907,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>")),
@@ -986,9 +1012,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>")),
@@ -1732,8 +1756,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);
@@ -1918,9 +1941,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);
@@ -3936,7 +3957,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])
@@ -4497,10 +4518,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));
@@ -4667,9 +4685,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.14.5

@ -0,0 +1,126 @@
From 2f6b827e89305adcff45288c632785ac054adb8e Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:36:30 +0100
Subject: [PATCH 16/26] Turn on creating/sending of DUID
Cc: pzhukov@redhat.com
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 8e57da9..ccc98e4 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -4021,6 +4021,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
@@ -4041,6 +4094,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;
@@ -4061,9 +4115,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.
@@ -4074,13 +4135,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.14.5

@ -0,0 +1,77 @@
From 193c4d7631fd623efa601f52fdab6018bf8be771 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:39:36 +0100
Subject: [PATCH 17/26] Send unicast request/release via correct interface
Cc: pzhukov@redhat.com
(#800561, #1177351)
(Submitted to dhcp-bugs@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 ccc98e4..27fde69 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -3171,6 +3171,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);
@@ -3180,6 +3188,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. */
@@ -3297,6 +3312,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);
@@ -3306,6 +3329,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.14.5

@ -0,0 +1,63 @@
From 2277d041692b8ebdf6b86d41e3a0bc0381cd1e47 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:40:51 +0100
Subject: [PATCH 18/26] No subnet declaration for <iface>' should be info, not
error.
Cc: pzhukov@redhat.com
---
common/discover.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/common/discover.c b/common/discover.c
index 65881fc..056342c 100644
--- a/common/discover.c
+++ b/common/discover.c
@@ -801,9 +801,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" :
@@ -818,26 +818,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.14.5

@ -0,0 +1,29 @@
From 6ea56e988df1da51f7d0bdd8984b38e40102c17b Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:41:14 +0100
Subject: [PATCH 19/26] dhclient: write DUID_LLT even in stateless mode
(#1156356)
Cc: pzhukov@redhat.com
(Submitted to dhcp-bugs@isc.org - [ISC-Bugs #38144])
---
client/dhclient.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/client/dhclient.c b/client/dhclient.c
index 27fde69..4e5546a 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -1442,6 +1442,9 @@ void run_stateless(int exit_mode, u_int16_t port)
data_string_forget(&default_duid, MDL);
form_duid(&default_duid, MDL);
+ if (form_duid(&default_duid, MDL) == ISC_R_SUCCESS &&
+ duid_type == DUID_LLT)
+ write_duid(&default_duid);
}
#ifdef DHCP4o6
--
2.14.5

@ -0,0 +1,101 @@
From 01ce61b8a0331a2f068ca2191bfb897b505c1b9d Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 21 Feb 2019 10:42:50 +0100
Subject: [PATCH 20/26] Discover all hwaddress for xid uniqueness
Cc: pzhukov@redhat.com
---
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 056342c..e66e1c5 100644
--- a/common/discover.c
+++ b/common/discover.c
@@ -648,6 +648,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 b732a86..a708a5d 100644
--- a/common/lpf.c
+++ b/common/lpf.c
@@ -699,8 +699,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;
@@ -710,7 +724,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");
@@ -794,14 +809,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 0c1a0aa..635c510 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -2637,7 +2637,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.14.5

@ -0,0 +1,50 @@
commit 50c2b3ba8ce030a47b55dd707bb8a6ab20444a05
Author: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu Feb 21 10:44:06 2019 +0100
Load leases DB in non-replay mode only
diff --git a/server/confpars.c b/server/confpars.c
index 2743979..6b61964 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;
}

@ -0,0 +1,80 @@
From 9975d198a2c02e32c31c3e0f43d2aa79dfa7f508 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 28 Feb 2019 15:30:21 +0100
Subject: [PATCH 22/26] dhclient: make sure link-local address is ready in
stateless mode
Cc: pzhukov@redhat.com
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 4e5546a..9b65438 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -937,6 +937,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) ||
@@ -953,12 +959,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);
@@ -1413,20 +1413,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.14.5

@ -0,0 +1,247 @@
From 6fd7894ea57791c8eee16c21d19da34b909e016e Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 28 Feb 2019 16:40:38 +0100
Subject: [PATCH 23/26] option 97 - pxe-client-id
Cc: pzhukov@redhat.com
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 3034cf0..686dd12 100644
--- a/common/options.c
+++ b/common/options.c
@@ -4465,13 +4465,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 f1be07d..4419220 100644
--- a/common/tables.c
+++ b/common/tables.c
@@ -196,8 +196,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 4cc547a..4eb9791 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_SUBNET_SELECTION 118 /* RFC3011! */
#define DHO_DOMAIN_SEARCH 119 /* RFC3397 */
#define DHO_CLASSLESS_STATIC_ROUTES 121 /* RFC3442 */
diff --git a/server/dhcp.c b/server/dhcp.c
index 0582c4c..4e86262 100644
--- a/server/dhcp.c
+++ b/server/dhcp.c
@@ -222,6 +222,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;
@@ -820,6 +824,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,
@@ -1331,6 +1338,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,
@@ -2441,6 +2451,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,
@@ -3033,6 +3046,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,
@@ -4150,6 +4166,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 89b5540..4751a8b 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 7be0788..2fee698 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 72f7b00..40fa691 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 052df67..8851366 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.14.5

@ -0,0 +1,93 @@
From 41c6032ace65119e6a400365f7e90283c930afd4 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Tue, 22 Oct 2019 16:23:01 +0200
Subject: [PATCH 24/26] Detect system time changes
Cc: pzhukov@redhat.com
---
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 9b65438..44d508a 100644
--- a/client/dhclient.c
+++ b/client/dhclient.c
@@ -5408,6 +5408,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 d7fe200..8a24499 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 635c510..ec6c227 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 530a923..4aef16b 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.14.5

@ -0,0 +1,197 @@
From ef4f5e80d8a1ea1507829ea6f5214f276478f475 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Tue, 22 Oct 2019 16:23:24 +0200
Subject: [PATCH 25/27] bind: Detect system time changes
Cc: pzhukov@redhat.com
---
bind/bind/lib/isc/include/isc/result.h | 4 ++-
bind/bind/lib/isc/include/isc/util.h | 4 +++
bind/bind/lib/isc/result.c | 2 ++
bind/bind/lib/isc/unix/app.c | 41 ++++++++++++++++++++++++++++---
bind/bind/lib/isc/unix/include/isc/time.h | 20 +++++++++++++++
bind/bind/lib/isc/unix/time.c | 22 +++++++++++++++++
6 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/bind/bind/lib/isc/include/isc/result.h b/bind/bind/lib/isc/include/isc/result.h
index 0389efa..0e35f98 100644
--- a/bind/bind/lib/isc/include/isc/result.h
+++ b/bind/bind/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/lib/isc/include/isc/util.h b/bind/bind/lib/isc/include/isc/util.h
index 973c348..cceeb5e 100644
--- a/bind/bind/lib/isc/include/isc/util.h
+++ b/bind/bind/lib/isc/include/isc/util.h
@@ -289,6 +289,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/lib/isc/result.c b/bind/bind/lib/isc/result.c
index a9db132..7c04831 100644
--- a/bind/bind/lib/isc/result.c
+++ b/bind/bind/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/lib/isc/unix/app.c b/bind/bind/lib/isc/unix/app.c
index a6e9882..dbd23f7 100644
--- a/bind/bind/lib/isc/unix/app.c
+++ b/bind/bind/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/lib/isc/unix/include/isc/time.h b/bind/bind/lib/isc/unix/include/isc/time.h
index b864c29..5dd43c9 100644
--- a/bind/bind/lib/isc/unix/include/isc/time.h
+++ b/bind/bind/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/lib/isc/unix/time.c b/bind/bind/lib/isc/unix/time.c
index 8edc9df..fe0bb91 100644
--- a/bind/bind/lib/isc/unix/time.c
+++ b/bind/bind/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.14.5

@ -0,0 +1,24 @@
commit 6acfd3125546a0e5db8fae8a9964cd2f88bf68c0
Author: Pavel Zhukov <pzhukov@redhat.com>
Date: Tue Oct 22 16:28:04 2019 +0200
Add dhclient(5) -B option description
Bug-Url: https://bugzilla.redhat.com/1764088
diff --git a/client/dhclient.8 b/client/dhclient.8
index 0145b9f..5226de5 100644
--- a/client/dhclient.8
+++ b/client/dhclient.8
@@ -552,6 +552,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

@ -0,0 +1,97 @@
From 8d974fd1f667e1b957ad4092fe66a8bb94f5f8fd Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Thu, 7 Nov 2019 14:47:45 +0100
Subject: [PATCH 1/1] Add missed sd notify patch to manage dhcpd with systemd
Cc: pzhukov@redhat.com
---
configure.ac | 11 +++++++++++
relay/dhcrelay.c | 12 ++++++++++++
server/dhcpd.c | 12 ++++++++++++
3 files changed, 35 insertions(+)
diff --git a/configure.ac b/configure.ac
index 15fc0d7..0c08000 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1014,6 +1014,17 @@ if test x$ldap = xyes || test x$ldapcrypto = xyes || test x$ldap_gssapi = xyes;
AC_SUBST(LDAP_CFLAGS, [$LDAP_CFLAGS])
fi
+AC_ARG_WITH(systemd,
+ AC_HELP_STRING([--with-systemd],
+ [enable sending status notifications to systemd daemon (default is no)]),
+ [systemd=$withval],
+ [systemd=no])
+
+if test x$systemd = xyes ; then
+ AC_CHECK_LIB(systemd, sd_notifyf, ,
+ AC_MSG_FAILURE([*** systemd library not present - do you need to install systemd-libs package?]))
+fi
+
# Append selected warning levels to CFLAGS before substitution (but after
# AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[],[]) & etc).
CFLAGS="$CFLAGS $STD_CWARNINGS"
diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c
index 7b4f4f1..9eb5bfd 100644
--- a/relay/dhcrelay.c
+++ b/relay/dhcrelay.c
@@ -37,6 +37,10 @@
int keep_capabilities = 0;
#endif
+#ifdef HAVE_LIBSYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
TIME default_lease_time = 43200; /* 12 hours... */
TIME max_lease_time = 86400; /* 24 hours... */
struct tree_cache *global_options[256];
@@ -845,6 +849,14 @@ main(int argc, char **argv) {
}
#endif
+#ifdef HAVE_LIBSYSTEMD
+ /* We are ready to process incomming packets. Let's notify systemd */
+ sd_notifyf(0, "READY=1\n"
+ "STATUS=Dispatching packets...\n"
+ "MAINPID=%lu",
+ (unsigned long) getpid());
+#endif
+
/* Start dispatching packets and timeouts... */
dispatch();
diff --git a/server/dhcpd.c b/server/dhcpd.c
index 4aef16b..778ef8d 100644
--- a/server/dhcpd.c
+++ b/server/dhcpd.c
@@ -60,6 +60,10 @@ gid_t set_gid = 0;
struct class unknown_class;
struct class known_class;
+#ifdef HAVE_LIBSYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
struct iaddr server_identifier;
int server_identifier_matched;
@@ -1057,6 +1061,14 @@ main(int argc, char **argv) {
/* Log that we are about to start working */
log_info("Server starting service.");
+#ifdef HAVE_LIBSYSTEMD
+ /* We are ready to process incomming packets. Let's notify systemd */
+ sd_notifyf(0, "READY=1\n"
+ "STATUS=Dispatching packets...\n"
+ "MAINPID=%lu",
+ (unsigned long) getpid());
+#endif
+
/*
* Receive packets and dispatch them...
* dispatch() will never return.
--
2.14.5

@ -0,0 +1,34 @@
From 02b4ae1953d39f1b6c3f0e63aefb72114039ab50 Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Tue, 22 Jun 2021 06:56:29 +0200
Subject: [PATCH 28/29] Fix for CVE-2021-25217
Cc: pzhukov@redhat.com
---
common/parse.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/common/parse.c b/common/parse.c
index f17bc0b..4e8b408 100644
--- a/common/parse.c
+++ b/common/parse.c
@@ -5587,13 +5587,14 @@ int parse_X (cfile, buf, max)
skip_to_semi (cfile);
return 0;
}
- convert_num (cfile, &buf [len], val, 16, 8);
- if (len++ > max) {
+ if (len >= max) {
parse_warn (cfile,
"hexadecimal constant too long.");
skip_to_semi (cfile);
return 0;
}
+ convert_num (cfile, &buf [len], val, 16, 8);
+ len++;
token = peek_token (&val, (unsigned *)0, cfile);
if (token == COLON)
token = next_token (&val,
--
2.26.3

@ -0,0 +1,118 @@
From 019021caa791c254a319c71b4f634142dc14b37d Mon Sep 17 00:00:00 2001
From: Pavel Zhukov <pzhukov@redhat.com>
Date: Tue, 22 Jun 2021 06:58:40 +0200
Subject: [PATCH 29/29] Use system getaddrinfo for dhcp
Cc: pzhukov@redhat.com
---
bind/bind/lib/irs/include/irs/netdb.h.in | 94 ++++++++++++++++++++++++
1 file changed, 94 insertions(+)
diff --git a/bind/bind/lib/irs/include/irs/netdb.h.in b/bind/bind/lib/irs/include/irs/netdb.h.in
index 23dcd37..f36113d 100644
--- a/bind/bind/lib/irs/include/irs/netdb.h.in
+++ b/bind/bind/lib/irs/include/irs/netdb.h.in
@@ -149,6 +149,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.26.3

@ -0,0 +1,37 @@
#!/bin/bash
# run dhclient.d scripts in an emulated environment
PATH=/bin:/usr/bin:/sbin
ETCDIR=/etc/dhcp
SAVEDIR=/var/lib/dhclient
interface=$1
for optname in "${!DHCP4_@}"; do
newoptname=${optname,,};
newoptname=new_${newoptname#dhcp4_};
export "${newoptname}"="${!optname}";
done
[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
[ -f /etc/sysconfig/network-scripts/ifcfg-"${interface}" ] && \
. /etc/sysconfig/network-scripts/ifcfg-"${interface}"
if [ -d $ETCDIR/dhclient.d ]; then
for f in $ETCDIR/dhclient.d/*.sh; do
if [ -x "${f}" ]; then
subsystem="${f%.sh}"
subsystem="${subsystem##*/}"
. "${f}"
if [ "$2" = "up" ]; then
"${subsystem}_config"
elif [ "$2" = "dhcp4-change" ]; then
if [ "$subsystem" = "chrony" -o "$subsystem" = "ntp" ]; then
"${subsystem}_config"
fi
elif [ "$2" = "down" ]; then
"${subsystem}_restore"
fi
fi
done
fi

@ -0,0 +1,61 @@
#!/bin/sh
# If we are running dhclient, shutdown running instances cleanly and
# bring them back up on resume.
. "${PM_FUNCTIONS}"
PM_DHCLIENT_RUNDIR="${PM_UTILS_RUNDIR}/network"
PM_DHCLIENT_SUSPEND="${PM_DHCLIENT_RUNDIR}/dhclient.suspend"
suspend_dhclient() {
[ ! -d /etc/sysconfig/network-scripts ] && return
[ ! -x /sbin/ifdown ] && return
[ ! -d ${PM_DHCLIENT_RUNDIR} ] && /bin/mkdir -p ${PM_DHCLIENT_RUNDIR}
[ -f ${PM_DHCLIENT_SUSPEND} ] && /bin/rm -f ${PM_DHCLIENT_SUSPEND}
cd /etc/sysconfig/network-scripts
for ifcfg in ifcfg-* ; do
# Clear relevant parameters set by previous interface
# (lo doesn't set them)
NM_CONTROLLED=
BOOTPROTO=
. ./"${ifcfg}"
if [ "${NM_CONTROLLED}" = "no" ] || [ "${NM_CONTROLLED}" = "n" ] || [ "${NM_CONTROLLED}" = "false" ]; then
if [ "${BOOTPROTO}" = "bootp" ] || [ "${BOOTPROTO}" = "dhcp" ] || [ -z "${BOOTPROTO}" ]; then
# device is not NetworkManager controlled and uses dhcp,
# now see if it's actually up at the moment
/sbin/ip link show ${DEVICE} | /bin/grep -qE "state (UP|UNKNOWN)" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "${DEVICE}" >> ${PM_DHCLIENT_SUSPEND}
/sbin/ifdown ${DEVICE}
fi
fi
fi
done
}
resume_dhclient() {
[ ! -f ${PM_DHCLIENT_SUSPEND} ] && return
[ ! -x /sbin/ifup ] && return
cd /etc/sysconfig/network-scripts
while read device ; do
/sbin/ifup ${device}
done < ${PM_DHCLIENT_SUSPEND}
/bin/rm -f ${PM_DHCLIENT_SUSPEND}
}
case "$1" in
hibernate|suspend)
suspend_dhclient
;;
thaw|resume)
resume_dhclient
;;
*) exit $NA
;;
esac

@ -0,0 +1,200 @@
diff --git a/bind/bind-9.11.14/lib/dns/resolver.c b/bind/bind-9.11.14/lib/dns/resolver.c
index e24499e..969bb9e 100644
--- a/bind/bind-9.11.14/lib/dns/resolver.c
+++ b/bind/bind-9.11.14/lib/dns/resolver.c
@@ -63,6 +63,7 @@
#include <dns/stats.h>
#include <dns/tsig.h>
#include <dns/validator.h>
+#include <dns/zone.h>
#ifdef WANT_QUERYTRACE
#define RTRACE(m) isc_log_write(dns_lctx, \
@@ -303,6 +304,8 @@ struct fetchctx {
bool ns_ttl_ok;
uint32_t ns_ttl;
isc_counter_t * qc;
+ dns_fixedname_t fwdfname;
+ dns_name_t *fwdname;
/*%
* The number of events we're waiting for.
@@ -3344,6 +3347,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) {
if (result == ISC_R_SUCCESS) {
fwd = ISC_LIST_HEAD(forwarders->fwdrs);
fctx->fwdpolicy = forwarders->fwdpolicy;
+ dns_name_copy(domain, fctx->fwdname, NULL);
if (fctx->fwdpolicy == dns_fwdpolicy_only &&
isstrictsubdomain(domain, &fctx->domain)) {
fcount_decr(fctx);
@@ -4368,6 +4372,9 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
fctx->restarts = 0;
fctx->querysent = 0;
fctx->referrals = 0;
+
+ fctx->fwdname = dns_fixedname_initname(&fctx->fwdfname);
+
TIME_NOW(&fctx->start);
fctx->timeouts = 0;
fctx->lamecount = 0;
@@ -4421,8 +4428,10 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
domain = dns_fixedname_initname(&fixed);
result = dns_fwdtable_find2(fctx->res->view->fwdtable, fwdname,
domain, &forwarders);
- if (result == ISC_R_SUCCESS)
+ if (result == ISC_R_SUCCESS) {
fctx->fwdpolicy = forwarders->fwdpolicy;
+ dns_name_copy(domain, fctx->fwdname, NULL);
+ }
if (fctx->fwdpolicy != dns_fwdpolicy_only) {
/*
@@ -6175,6 +6184,112 @@ mark_related(dns_name_t *name, dns_rdataset_t *rdataset,
rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL;
}
+/*
+ * Returns true if 'name' is external to the namespace for which
+ * the server being queried can answer, either because it's not a
+ * subdomain or because it's below a forward declaration or a
+ * locally served zone.
+ */
+static inline bool
+name_external(dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
+ isc_result_t result;
+ dns_forwarders_t *forwarders = NULL;
+ dns_fixedname_t fixed, zfixed;
+ dns_name_t *fname = dns_fixedname_initname(&fixed);
+ dns_name_t *zfname = dns_fixedname_initname(&zfixed);
+ dns_name_t *apex = NULL;
+ dns_name_t suffix;
+ dns_zone_t *zone = NULL;
+ unsigned int labels;
+ dns_namereln_t rel;
+ /*
+ * The following two variables do not influence code flow; they are
+ * only necessary for calling dns_name_fullcompare().
+ */
+ int _orderp = 0;
+ unsigned int _nlabelsp = 0;
+
+ apex = ISFORWARDER(fctx->addrinfo) ? fctx->fwdname : &fctx->domain;
+
+ /*
+ * The name is outside the queried namespace.
+ */
+ rel = dns_name_fullcompare(name, apex, &_orderp, &_nlabelsp);
+ if (rel != dns_namereln_subdomain && rel != dns_namereln_equal) {
+ return (true);
+ }
+
+ /*
+ * If the record lives in the parent zone, adjust the name so we
+ * look for the correct zone or forward clause.
+ */
+ labels = dns_name_countlabels(name);
+ if (dns_rdatatype_atparent(type) && labels > 1U) {
+ dns_name_init(&suffix, NULL);
+ dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
+ name = &suffix;
+ } else if (rel == dns_namereln_equal) {
+ /* If 'name' is 'apex', no further checking is needed. */
+ return (false);
+ }
+
+ /*
+ * If there is a locally served zone between 'apex' and 'name'
+ * then don't cache.
+ */
+ LOCK(&fctx->res->view->lock);
+ if (fctx->res->view->zonetable != NULL) {
+ unsigned int options = DNS_ZTFIND_NOEXACT;
+ result = dns_zt_find(fctx->res->view->zonetable, name, options,
+ zfname, &zone);
+ if (zone != NULL) {
+ dns_zone_detach(&zone);
+ }
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ if (dns_name_fullcompare(zfname, apex, &_orderp,
+ &_nlabelsp) ==
+ dns_namereln_subdomain)
+ {
+ UNLOCK(&fctx->res->view->lock);
+ return (true);
+ }
+ }
+ }
+ UNLOCK(&fctx->res->view->lock);
+
+ /*
+ * Look for a forward declaration below 'name'.
+ */
+ result = dns_fwdtable_find2(fctx->res->view->fwdtable, name, fname,
+ &forwarders);
+
+ if (ISFORWARDER(fctx->addrinfo)) {
+ /*
+ * See if the forwarder declaration is better.
+ */
+ if (result == ISC_R_SUCCESS) {
+ return (!dns_name_equal(fname, fctx->fwdname));
+ }
+
+ /*
+ * If the lookup failed, the configuration must have
+ * changed: play it safe and don't cache.
+ */
+ return (true);
+ } else if (result == ISC_R_SUCCESS &&
+ forwarders->fwdpolicy == dns_fwdpolicy_only &&
+ !ISC_LIST_EMPTY(forwarders->fwdrs))
+ {
+ /*
+ * If 'name' is covered by a 'forward only' clause then we
+ * can't cache this repsonse.
+ */
+ return (true);
+ }
+
+ return (false);
+}
+
static isc_result_t
check_section(void *arg, dns_name_t *addname, dns_rdatatype_t type,
dns_section_t section)
@@ -6201,7 +6316,7 @@ check_section(void *arg, dns_name_t *addname, dns_rdatatype_t type,
result = dns_message_findname(fctx->rmessage, section, addname,
dns_rdatatype_any, 0, &name, NULL);
if (result == ISC_R_SUCCESS) {
- external = !dns_name_issubdomain(name, &fctx->domain);
+ external = name_external(name, type, fctx);
if (type == dns_rdatatype_a) {
for (rdataset = ISC_LIST_HEAD(name->list);
rdataset != NULL;
@@ -7071,6 +7186,13 @@ answer_response(fetchctx_t *fctx) {
break;
case dns_namereln_subdomain:
+ /*
+ * Don't accept DNAME from parent namespace.
+ */
+ if (name_external(name, dns_rdatatype_dname, fctx)) {
+ continue;
+ }
+
/*
* In-scope DNAME records must have at least
* as many labels as the domain being queried.
@@ -7299,11 +7421,9 @@ answer_response(fetchctx_t *fctx) {
*/
result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
while (!done && result == ISC_R_SUCCESS) {
- bool external;
name = NULL;
dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
- external = !dns_name_issubdomain(name, &fctx->domain);
- if (!external) {
+ if (!name_external(name, dns_rdatatype_ns, fctx)) {
/*
* We expect to find NS or SIG NS rdatasets, and
* nothing else.

@ -0,0 +1,47 @@
The /etc/dhcp/dhclient.d directory allows other packages and system
administrators to create application-specific option handlers for dhclient.
When dhclient is run, any option listed in the dhcp-options(5) man page can
be requested. dhclient-script does not handle every option available
because doing so would make the script unmaintainable as the components
using those options might change over time. The knowledge of how to handle
those options should be under the responsibility of the package maintainer
for that component (e.g., NTP options belong in a handler in the ntp
package).
To make maintenance easier, application specific DHCP options can be handled
by creating a bash script with two functions and placing it in /etc/dhcp/dhclient.d
The script must follow a specific form:
(1) The script must be named NAME.sh. NAME can be anything, but it makes
sense to name it for the service it handles. e.g., ntp.sh
(2) The script must provide a NAME_config() function to read the options and
do whatever it takes to put those options in place.
(3) The script must provide a NAME_restore() function to restore original
configuration state when dhclient stops.
(4) The script must be 'chmod +x' or dhclient-script will ignore it.
The scripts execute in the same environment as dhclient-script. That means
all of the functions and variables available to it are available to your
NAME.sh script. Things of note:
${SAVEDIR} is where original configuration files are saved. Save your
original configuration files here before you take the DHCP provided
values and generate new files.
Variables set in /etc/sysconfig/network, /etc/sysconfig/networking/network,
and /etc/sysconfig/network-scripts/ifcfg-$interface are available to
you.
See the scripts in /etc/dhcp/dhclient.d for examples.
NOTE: Do not use functions defined in /usr/sbin/dhclient-script. Consider
dhclient-script a black box. This script may change over time, so the
dhclient.d scripts should not be using functions defined in it.
--
David Cantrell <dcantrell@redhat.com>

@ -0,0 +1,975 @@
#!/bin/bash
#
# dhclient-script: Network interface configuration script run by
# dhclient based on DHCP client communication
#
# Copyright (C) 2008-2014 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Author(s): David Cantrell <dcantrell@redhat.com>
# Jiri Popelka <jpopelka@redhat.com>
#
# ----------
# This script is a rewrite/reworking on dhclient-script originally
# included as part of dhcp-970306:
# dhclient-script for Linux. Dan Halbert, March, 1997.
# Updated for Linux 2.[12] by Brian J. Murrell, January 1999.
# Modified by David Cantrell <dcantrell@redhat.com> for Fedora and RHEL
# ----------
#
PATH=/bin:/usr/bin:/sbin
# scripts in dhclient.d/ use $SAVEDIR (#833054)
export SAVEDIR=/var/lib/dhclient
LOGFACILITY="local7"
LOGLEVEL="notice"
ETCDIR="/etc/dhcp"
RESOLVCONF="/etc/resolv.conf"
logmessage() {
msg="${1}"
logger -p "${LOGFACILITY}.${LOGLEVEL}" -t "NET" "dhclient: ${msg}"
}
eventually_add_hostnames_domain_to_search() {
# For the case when hostname for this machine has a domain that is not in domain_search list
# 1) get a hostname with `ipcalc --hostname` or `hostnamectl --transient`
# 2) get the domain from this hostname
# 3) add this domain to search line in resolv.conf if it's not already
# there (domain list that we have recently added there is a parameter of this function)
# We can't do this directly when generating resolv.conf in make_resolv_conf(), because
# we need to first save the resolv.conf with obtained values before we can call `ipcalc --hostname`.
# See bug 637763
search="${1}"
if need_hostname; then
status=1
OLD_HOSTNAME=$HOSTNAME
if [ -n "${new_ip_address}" ]; then
eval $(/usr/bin/ipcalc --silent --hostname "${new_ip_address}" ; echo "status=$?")
elif [ -n "${new_ip6_address}" ]; then
eval $(/usr/bin/ipcalc --silent --hostname "${new_ip6_address}" ; echo "status=$?")
fi
if [ ${status} -eq 0 ]; then
domain=$(echo "${HOSTNAME}" | cut -s -d "." -f 2-)
fi
HOSTNAME=$OLD_HOSTNAME
else
domain=$(hostnamectl --transient 2>/dev/null | cut -s -d "." -f 2-)
fi
if [ -n "${domain}" ] &&
[ ! "${domain}" = "localdomain" ] &&
[ ! "${domain}" = "localdomain6" ] &&
[ ! "${domain}" = "(none)" ] &&
[[ ! "${domain}" = *\ * ]]; then
is_in="false"
for s in ${search}; do
if [ "${s}" = "${domain}" ] ||
[ "${s}" = "${domain}." ]; then
is_in="true"
fi
done
if [ "${is_in}" = "false" ]; then
# Add domain name to search list (#637763)
sed -i -e "s/${search}/${search} ${domain}/" "${RESOLVCONF}"
fi
fi
}
make_resolv_conf() {
[ "${PEERDNS}" = "no" ] && return
if [ "${reason}" = "RENEW" ] &&
[ "${new_domain_name}" = "${old_domain_name}" ] &&
[ "${new_domain_name_servers}" = "${old_domain_name_servers}" ]; then
return
fi
if [ -n "${new_domain_name}" ] ||
[ -n "${new_domain_name_servers}" ] ||
[ -n "${new_domain_search}" ]; then
rscf="$(mktemp "${TMPDIR:-/tmp}/XXXXXX")"
[[ -z "${rscf}" ]] && return
echo "; generated by /usr/sbin/dhclient-script" > "${rscf}"
if [ -n "${SEARCH}" ]; then
search="${SEARCH}"
else
if [ -n "${new_domain_search}" ]; then
# Remove instaces of \032 (#450042)
search="${new_domain_search//\\032/ }"
elif [ -n "${new_domain_name}" ]; then
# Note that the DHCP 'Domain Name Option' is really just a domain
# name, and that this practice of using the domain name option as
# a search path is both nonstandard and deprecated.
search="${new_domain_name}"
fi
fi
if [ -n "${search}" ]; then
echo "search ${search}" >> "${rscf}"
fi
if [ -n "${RES_OPTIONS}" ]; then
echo "options ${RES_OPTIONS}" >> "${rscf}"
fi
if [ -n "${new_domain_name_servers}" ]; then
for nameserver in ${new_domain_name_servers} ; do
echo "nameserver ${nameserver}" >> "${rscf}"
done
else # keep 'old' nameservers
sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p "${RESOLVCONF}" >> "${rscf}"
fi
change_resolv_conf "${rscf}"
rm -f "${rscf}"
if [ -n "${search}" ]; then
eventually_add_hostnames_domain_to_search "${search}"
fi
elif [ -n "${new_dhcp6_name_servers}" ] ||
[ -n "${new_dhcp6_domain_search}" ]; then
rscf="$(mktemp "${TMPDIR:-/tmp}/XXXXXX")"
[[ -z "${rscf}" ]] && return
echo "; generated by /usr/sbin/dhclient-script" > "${rscf}"
if [ -n "${SEARCH}" ]; then
search="${SEARCH}"
else
if [ -n "${new_dhcp6_domain_search}" ]; then
search="${new_dhcp6_domain_search//\\032/ }"
fi
fi
if [ -n "${search}" ]; then
echo "search ${search}" >> "${rscf}"
fi
if [ -n "${RES_OPTIONS}" ]; then
echo "options ${RES_OPTIONS}" >> "${rscf}"
fi
shopt -s nocasematch
if [ -n "${new_dhcp6_name_servers}" ]; then
for nameserver in ${new_dhcp6_name_servers} ; do
# If the nameserver has a link-local address
# add a <zone_id> (interface name) to it.
if [[ "$nameserver" =~ ^fe80:: ]]
then
zone_id="%${interface}"
else
zone_id=
fi
echo "nameserver ${nameserver}$zone_id" >> "${rscf}"
done
else # keep 'old' nameservers
sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p "${RESOLVCONF}" >> "${rscf}"
fi
shopt -u nocasematch
change_resolv_conf "${rscf}"
rm -f "${rscf}"
if [ -n "${search}" ]; then
eventually_add_hostnames_domain_to_search "${search}"
fi
fi
}
# run given script
run_hook() {
local script
local exit_status
script="${1}"
if [ -f ${script} ]; then
. ${script}
fi
if [ -n "${exit_status}" ] && [ "${exit_status}" -ne 0 ]; then
logmessage "${script} returned non-zero exit status ${exit_status}"
fi
return ${exit_status}
}
# run scripts in given directory
run_hookdir() {
local dir
dir="${1}"
if [ -d "${dir}" ]; then
for script in $(find $dir -executable ! -empty); do
run_hook ${script} || return $?
done
fi
return 0
}
exit_with_hooks() {
# Source the documented exit-hook script, if it exists
run_hook "${ETCDIR}/dhclient-exit-hooks" || exit $?
# Now run scripts in the hooks directory.
run_hookdir "${ETCDIR}/dhclient-exit-hooks.d" || exit $?
exit ${1}
}
quad2num() {
if [ $# -eq 4 ]; then
let n="${1} << 24 | ${2} << 16 | ${3} << 8 | ${4}"
echo "${n}"
return 0
else
echo "0"
return 1
fi
}
ip2num() {
IFS='.' quad2num ${1}
}
num2ip() {
let n="${1}"
let o1="(${n} >> 24) & 0xff"
let o2="(${n} >> 16) & 0xff"
let o3="(${n} >> 8) & 0xff"
let o4="${n} & 0xff"
echo "${o1}.${o2}.${o3}.${o4}"
}
get_network_address() {
# get network address for the given IP address and (netmask or prefix)
ip="${1}"
nm="${2}"
if [ -n "${ip}" -a -n "${nm}" ]; then
if [[ "${nm}" = *.* ]]; then
ipcalc -s -n "${ip}" "${nm}" | cut -d '=' -f 2
else
ipcalc -s -n "${ip}/${nm}" | cut -d '=' -f 2
fi
fi
}
get_prefix() {
# get prefix for the given IP address and mask
ip="${1}"
nm="${2}"
if [ -n "${ip}" -a -n "${nm}" ]; then
ipcalc -s -p "${ip}" "${nm}" | cut -d '=' -f 2
fi
}
class_bits() {
let ip=$(IFS='.' ip2num "${1}")
let bits=32
let mask='255'
for ((i=0; i <= 3; i++, 'mask<<=8')); do
let v='ip&mask'
if [ "$v" -eq 0 ] ; then
let bits-=8
else
break
fi
done
echo $bits
}
is_router_reachable() {
# handle DHCP servers that give us a router not on our subnet
router="${1}"
routersubnet="$(get_network_address "${router}" "${new_subnet_mask}")"
mysubnet="$(get_network_address "${new_ip_address}" "${new_subnet_mask}")"
if [ ! "${routersubnet}" = "${mysubnet}" ]; then
# TODO: This function should not have side effects such as adding or
# removing routes. Can this be done with "ip route get" or similar
# instead? Are there cases that rely on this route being created here?
ip -4 route replace "${router}/32" dev "${interface}"
if [ "$?" -ne 0 ]; then
logmessage "failed to create host route for ${router}"
return 1
fi
fi
return 0
}
add_default_gateway() {
router="${1}"
if is_router_reachable "${router}" ; then
if [ $# -gt 1 ] && [ -n "${2}" ] && [[ "${2}" -gt 0 ]]; then
ip -4 route replace default via "${router}" dev "${interface}" metric "${2}"
else
ip -4 route replace default via "${router}" dev "${interface}"
fi
if [ $? -ne 0 ]; then
logmessage "failed to create default route: ${router} dev ${interface} ${metric}"
return 1
else
return 0
fi
fi
return 1
}
execute_client_side_configuration_scripts() {
# execute any additional client side configuration scripts we have
if [ "${1}" == "config" ] || [ "${1}" == "restore" ]; then
for f in ${ETCDIR}/dhclient.d/*.sh ; do
if [ -x "${f}" ]; then
subsystem="${f%.sh}"
subsystem="${subsystem##*/}"
. "${f}"
"${subsystem}_${1}"
fi
done
fi
}
flush_dev() {
# Instead of bringing the interface down (#574568)
# explicitly clear ARP cache and flush all addresses & routes.
ip -4 addr flush dev "${1}" >/dev/null 2>&1
ip -4 route flush dev "${1}" >/dev/null 2>&1
ip -4 neigh flush dev "${1}" >/dev/null 2>&1
}
remove_old_addr() {
if [ -n "${old_ip_address}" ]; then
if [ -n "${old_prefix}" ]; then
ip -4 addr del "${old_ip_address}/${old_prefix}" dev "${interface}" >/dev/null 2>&1
else
ip -4 addr del "${old_ip_address}" dev "${interface}" >/dev/null 2>&1
fi
fi
}
dhconfig() {
if [ -n "${old_ip_address}" ] && [ -n "${alias_ip_address}" ] &&
[ ! "${alias_ip_address}" = "${old_ip_address}" ]; then
# possible new alias, remove old alias first
ip -4 addr del "${old_ip_address}" dev "${interface}" label "${interface}:0"
fi
if [ -n "${old_ip_address}" ] &&
[ ! "${old_ip_address}" = "${new_ip_address}" ]; then
# IP address changed. Delete all routes, and clear the ARP cache.
flush_dev "${interface}"
fi
# make sure the interface is up
ip link set dev "${interface}" up
# replace = add if it doesn't exist or override (update lifetimes) if it's there
ip -4 addr replace "${new_ip_address}/${new_prefix}" broadcast "${new_broadcast_address}" dev "${interface}" \
valid_lft "${new_dhcp_lease_time}" preferred_lft "${new_dhcp_lease_time}" >/dev/null 2>&1
if [ "${reason}" = "BOUND" ] || [ "${reason}" = "REBOOT" ] ||
[ ! "${old_ip_address}" = "${new_ip_address}" ] ||
[ ! "${old_subnet_mask}" = "${new_subnet_mask}" ] ||
[ ! "${old_network_number}" = "${new_network_number}" ] ||
[ ! "${old_broadcast_address}" = "${new_broadcast_address}" ] ||
[ ! "${old_routers}" = "${new_routers}" ] ||
[ ! "${old_interface_mtu}" = "${new_interface_mtu}" ]; then
# The 576 MTU is only used for X.25 and dialup connections
# where the admin wants low latency. Such a low MTU can cause
# problems with UDP traffic, among other things. As such,
# disallow MTUs from 576 and below by default, so that broken
# MTUs are ignored, but higher stuff is allowed (1492, 1500, etc).
if [ -n "${new_interface_mtu}" ] && [ "${new_interface_mtu}" -gt 576 ]; then
ip link set dev "${interface}" mtu "${new_interface_mtu}"
fi
# static routes
if [ -n "${new_classless_static_routes}" ] ||
[ -n "${new_static_routes}" ]; then
if [ -n "${new_classless_static_routes}" ]; then
IFS=', |' static_routes=(${new_classless_static_routes})
# If the DHCP server returns both a Classless Static Routes option and
# a Router option, the DHCP client MUST ignore the Router option. (RFC3442)
new_routers=""
else
IFS=', |' static_routes=(${new_static_routes})
fi
route_targets=()
for((i=0; i<${#static_routes[@]}; i+=2)); do
target=${static_routes[$i]}
if [ -n "${new_classless_static_routes}" ]; then
if [ "${target}" = "0" ]; then
new_routers="${static_routes[$i+1]}"
continue
else
prefix=${target%%.*}
target=${target#*.}
IFS="." target_arr=(${target})
unset IFS
((pads=4-${#target_arr[@]}))
for j in $(seq $pads); do
target="${target}.0"
done
# Client MUST zero any bits in the subnet number where the corresponding bit in the mask is zero.
# In other words, the subnet number installed in the routing table is the logical AND of
# the subnet number and subnet mask given in the Classless Static Routes option. (RFC3442)
target="$(get_network_address "${target}" "${prefix}")"
fi
else
prefix=$(class_bits "${target}")
fi
gateway=${static_routes[$i+1]}
# special case 0.0.0.0 to allow static routing for link-local addresses
# (including IPv4 multicast) which will not have a next-hop (#769463, #787318)
if [ "${gateway}" = "0.0.0.0" ]; then
valid_gateway=0
scope='scope link'
else
is_router_reachable "${gateway}"
valid_gateway=$?
scope=''
fi
if [ "${valid_gateway}" -eq 0 ]; then
metric=''
for t in "${route_targets[@]}"; do
if [ "${t}" = "${target}" ]; then
if [ -z "${metric}" ]; then
metric=1
else
((metric=metric+1))
fi
fi
done
if [ -n "${metric}" ]; then
metric="metric ${metric}"
fi
ip -4 route replace "${target}/${prefix}" proto static via "${gateway}" dev "${interface}" ${metric} ${scope}
if [ $? -ne 0 ]; then
logmessage "failed to create static route: ${target}/${prefix} via ${gateway} dev ${interface} ${metric}"
else
route_targets=(${route_targets[@]} ${target})
fi
fi
done
fi
# gateways
if [[ ( "${DEFROUTE}" != "no" ) &&
(( -z "${GATEWAYDEV}" ) || ( "${GATEWAYDEV}" = "${interface}" )) ]]; then
if [[ ( -z "${GATEWAY}" ) ||
(( -n "${DHCLIENT_IGNORE_GATEWAY}" ) && ( "${DHCLIENT_IGNORE_GATEWAY}" = [Yy]* )) ]]; then
metric="${METRIC:-}"
let i="${METRIC:-0}"
default_routers=()
for router in ${new_routers} ; do
added_router=-
for r in "${default_routers[@]}" ; do
if [ "${r}" = "${router}" ]; then
added_router=1
fi
done
if [ -z "${router}" ] ||
[ "${added_router}" = "1" ] ||
[ "$(IFS='.' ip2num ${router})" -le 0 ] ||
[[ ( "${router}" = "${new_broadcast_address}" ) &&
( "${new_subnet_mask}" != "255.255.255.255" ) ]]; then
continue
fi
default_routers=(${default_routers[@]} ${router})
add_default_gateway "${router}" "${metric}"
let i=i+1
metric=${i}
done
elif [ -n "${GATEWAY}" ]; then
routersubnet=$(get_network_address "${GATEWAY}" "${new_subnet_mask}")
mysubnet=$(get_network_address "${new_ip_address}" "${new_subnet_mask}")
if [ "${routersubnet}" = "${mysubnet}" ]; then
ip -4 route replace default via "${GATEWAY}" dev "${interface}"
fi
fi
fi
fi
if [ ! "${new_ip_address}" = "${alias_ip_address}" ] &&
[ -n "${alias_ip_address}" ]; then
# Reset the alias address (fix: this should really only do this on changes)
ip -4 addr flush dev "${interface}" label "${interface}:0" >/dev/null 2>&1
ip -4 addr replace "${alias_ip_address}/${alias_prefix}" broadcast "${alias_broadcast_address}" dev "${interface}" label "${interface}:0"
ip -4 route replace "${alias_ip_address}/32" dev "${interface}"
fi
# After dhclient brings an interface UP with a new IP address, subnet mask,
# and routes, in the REBOOT/BOUND states -> search for "dhclient-up-hooks".
if [ "${reason}" = "BOUND" ] || [ "${reason}" = "REBOOT" ] ||
[ ! "${old_ip_address}" = "${new_ip_address}" ] ||
[ ! "${old_subnet_mask}" = "${new_subnet_mask}" ] ||
[ ! "${old_network_number}" = "${new_network_number}" ] ||
[ ! "${old_broadcast_address}" = "${new_broadcast_address}" ] ||
[ ! "${old_routers}" = "${new_routers}" ] ||
[ ! "${old_interface_mtu}" = "${new_interface_mtu}" ]; then
if [ -x "${ETCDIR}/dhclient-${interface}-up-hooks" ]; then
. "${ETCDIR}/dhclient-${interface}-up-hooks"
elif [ -x ${ETCDIR}/dhclient-up-hooks ]; then
. ${ETCDIR}/dhclient-up-hooks
fi
fi
make_resolv_conf
if [ -n "${new_host_name}" ] && need_hostname; then
hostnamectl set-hostname --transient --no-ask-password "${new_host_name}"
fi
if [[ ( "${DHCP_TIME_OFFSET_SETS_TIMEZONE}" = [yY1]* ) &&
( -n "${new_time_offset}" ) ]]; then
# DHCP option "time-offset" is requested by default and should be
# handled. The geographical zone abbreviation cannot be determined
# from the GMT offset, but the $ZONEINFO/Etc/GMT$offset file can be
# used - note: this disables DST.
((z=new_time_offset/3600))
((hoursWest=$(printf '%+d' $z)))
if (( $hoursWest < 0 )); then
# tzdata treats negative 'hours west' as positive 'gmtoff'!
((hoursWest*=-1))
fi
tzfile=/usr/share/zoneinfo/Etc/GMT$(printf '%+d' ${hoursWest})
if [ -e "${tzfile}" ]; then
cp -fp "${tzfile}" /etc/localtime
touch /etc/localtime
fi
fi
execute_client_side_configuration_scripts "config"
}
wait_for_link_local() {
# we need a link-local address to be ready (not tentative)
for i in $(seq 50); do
linklocal=$(ip -6 addr show dev "${interface}" scope link)
# tentative flag means DAD is still not complete
tentative=$(echo "${linklocal}" | grep tentative)
[[ -n "${linklocal}" && -z "${tentative}" ]] && exit_with_hooks 0
sleep 0.1
done
}
# Section 18.1.8. (Receipt of Reply Messages) of RFC 3315 says:
# The client SHOULD perform duplicate address detection on each of
# the addresses in any IAs it receives in the Reply message before
# using that address for traffic.
add_ipv6_addr_with_DAD() {
ip -6 addr replace "${new_ip6_address}/${new_ip6_prefixlen}" \
dev "${interface}" scope global valid_lft "${new_max_life}" \
preferred_lft "${new_preferred_life}"
# repeatedly test whether newly added address passed
# duplicate address detection (DAD)
for i in $(seq 5); do
sleep 1 # give the DAD some time
addr=$(ip -6 addr show dev "${interface}" \
| grep "${new_ip6_address}/${new_ip6_prefixlen}")
# tentative flag == DAD is still not complete
tentative=$(echo "${addr}" | grep tentative)
# dadfailed flag == address is already in use somewhere else
dadfailed=$(echo "${addr}" | grep dadfailed)
if [ -n "${dadfailed}" ] ; then
# address was added with valid_lft/preferred_lft 'forever', remove it
ip -6 addr del "${new_ip6_address}/${new_ip6_prefixlen}" dev "${interface}"
exit_with_hooks 3
fi
if [ -z "${tentative}" ] ; then
if [ -n "${addr}" ]; then
# DAD is over
return 0
else
# address was auto-removed (or not added at all)
exit_with_hooks 3
fi
fi
done
return 0
}
dh6config() {
if [ -n "${old_ip6_prefix}" ] ||
[ -n "${new_ip6_prefix}" ]; then
echo "Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix}"
exit_with_hooks 0
fi
case "${reason}" in
BOUND6)
if [ -z "${new_ip6_address}" ] ||
[ -z "${new_ip6_prefixlen}" ]; then
exit_with_hooks 2
fi
add_ipv6_addr_with_DAD
make_resolv_conf
;;
RENEW6|REBIND6)
if [[ -n "${new_ip6_address}" ]] &&
[[ -n "${new_ip6_prefixlen}" ]]; then
if [[ ! "${new_ip6_address}" = "${old_ip6_address}" ]]; then
[[ -n "${old_ip6_address}" ]] && ip -6 addr del "${old_ip6_address}" dev "${interface}"
fi
# call it even if new_ip6_address = old_ip6_address to update lifetimes
add_ipv6_addr_with_DAD
fi
if [ ! "${new_dhcp6_name_servers}" = "${old_dhcp6_name_servers}" ] ||
[ ! "${new_dhcp6_domain_search}" = "${old_dhcp6_domain_search}" ]; then
make_resolv_conf
fi
;;
DEPREF6)
if [ -z "${new_ip6_prefixlen}" ]; then
exit_with_hooks 2
fi
ip -6 addr change "${new_ip6_address}/${new_ip6_prefixlen}" \
dev "${interface}" scope global preferred_lft 0
;;
esac
execute_client_side_configuration_scripts "config"
}
# Functions from /etc/sysconfig/network-scripts/network-functions
need_hostname ()
{
CHECK_HOSTNAME=$(hostnamectl --transient)
if [[ "${CHECK_HOSTNAME}" = "(none)" ]] ||
[[ "${CHECK_HOSTNAME}" = "localhost" ]] ||
[[ "${CHECK_HOSTNAME}" = "localhost.localdomain" ]]; then
return 0
else
return 1
fi
}
# Takes one argument - temporary resolv.conf file
change_resolv_conf ()
{
options=$(grep '^[\ \ ]*option' "${RESOLVCONF}" 2>/dev/null);
if [[ -n "${options}" ]]; then
# merge options from existing resolv.conf with specified resolv.conf content
newres="${options}"$'\n'$(grep -vF "${options}" "${1}");
else
newres=$(cat "${1}");
fi;
eval $(echo "${newres}" > "${RESOLVCONF}"; echo "status=$?")
if [[ $status -eq 0 ]]; then
logger -p local7.notice -t "NET" -i "${0} : updated ${RESOLVCONF}";
[[ -e /var/run/nscd/socket ]] && /usr/sbin/nscd -i hosts; # invalidate cache
fi;
return $status;
}
get_config_by_name ()
{
LANG=C grep -E -i -l \
"^[[:space:]]*NAME=\"(Auto |System )?${1}\"" \
/etc/sysconfig/network-scripts/ifcfg-* \
| LC_ALL=C sed -e "$__sed_discard_ignored_files"
}
get_hwaddr ()
{
if [ -f /sys/class/net/${1}/address ]; then
awk '{ print toupper($0) }' < /sys/class/net/${1}/address
elif [ -d "/sys/class/net/${1}" ]; then
LC_ALL= LANG= ip -o link show ${1} 2>/dev/null | \
awk '{ print toupper(gensub(/.*link\/[^ ]* ([[:alnum:]:]*).*/,
"\\1", 1)); }'
fi
}
validate_resolv_conf()
{
# It's possible to have broken symbolic link $RESOLVCONF -> <some_nm_dir>
# https://bugzilla.redhat.com/1475279
# Remove broken link and hope NM will survive
if [ -h "${RESOLVCONF}" -a ! -e "${RESOLVCONF}" ];
then
logmessage "${RESOLVCONF} is broken symlink. Recreating..."
unlink "${RESOLVCONF}"
touch "${RESOLVCONF}"
fi;
}
get_config_by_hwaddr ()
{
LANG=C grep -il "^[[:space:]]*HWADDR=\"\?${1}\"\?\([[:space:]#]\|$\)" /etc/sysconfig/network-scripts/ifcfg-* \
| LC_ALL=C sed -e "$__sed_discard_ignored_files"
}
get_config_by_device ()
{
LANG=C grep -l "^[[:space:]]*DEVICE=\"\?${1}\"\?\([[:space:]#]\|$\)" \
/etc/sysconfig/network-scripts/ifcfg-* \
| LC_ALL=C sed -e "$__sed_discard_ignored_files"
}
need_config ()
{
# A sed expression to filter out the files that is_ignored_file recognizes
__sed_discard_ignored_files='/\(~\|\.bak\|\.orig\|\.rpmnew\|\.rpmorig\|\.rpmsave\)$/d'
local nconfig
CONFIG="ifcfg-${1}"
[ -f "${CONFIG}" ] && return
CONFIG="${1##*/}"
[ -f "${CONFIG}" ] && return
nconfig=$(get_config_by_name "${1}")
if [ -n "$nconfig" ] && [ -f "$nconfig" ]; then
CONFIG=${nconfig##*/}
return
fi
local addr=$(get_hwaddr ${1})
if [ -n "$addr" ]; then
nconfig=$(get_config_by_hwaddr ${addr})
if [ -n "$nconfig" ] ; then
CONFIG=${nconfig##*/}
[ -f "${CONFIG}" ] && return
fi
fi
nconfig=$(get_config_by_device ${1})
if [ -n "$nconfig" ] && [ -f "$nconfig" ]; then
CONFIG=${nconfig##*/}
return
fi
}
# We need this because of PEERDNS
source_config ()
{
CONFIG=${CONFIG##*/}
. /etc/sysconfig/network-scripts/$CONFIG
}
#
# ### MAIN
#
# Invoke the local dhcp client enter hooks, if they exist.
run_hook "${ETCDIR}/dhclient-enter-hooks" || exit $?
run_hookdir "${ETCDIR}/dhclient-enter-hooks.d" || exit $?
[ "${PEERDNS}" = "no" ] || validate_resolv_conf
if [ -f /etc/sysconfig/network ]; then
. /etc/sysconfig/network
fi
if [ -f /etc/sysconfig/networking/network ]; then
. /etc/sysconfig/networking/network
fi
## it's possible initscripts package is not installed
## for example in container. Don't flood stderr then
if [ -d /etc/sysconfig/network-scripts ]; then
cd /etc/sysconfig/network-scripts
CONFIG="${interface}"
need_config "${CONFIG}"
source_config >/dev/null 2>&1
fi;
# In case there's some delay in rebinding, it might happen, that the valid_lft drops to 0,
# address is removed by kernel and then re-added few seconds later by dhclient-script.
# With this work-around the address lives a minute longer.
# "4294967235" = infinite (forever) - 60
[[ "${new_dhcp_lease_time}" -lt "4294967235" ]] && new_dhcp_lease_time=$((new_dhcp_lease_time + 60))
[[ "${new_max_life}" -lt "4294967235" ]] && new_max_life=$((new_max_life + 60))
new_prefix="$(get_prefix "${new_ip_address}" "${new_subnet_mask}")"
old_prefix="$(get_prefix "${old_ip_address}" "${old_subnet_mask}")"
alias_prefix="$(get_prefix "${alias_ip_address}" "${alias_subnet_mask}")"
case "${reason}" in
MEDIUM|ARPCHECK|ARPSEND)
# Do nothing
exit_with_hooks 0
;;
PREINIT)
if [ -n "${alias_ip_address}" ]; then
# Flush alias, its routes will disappear too.
ip -4 addr flush dev "${interface}" label "${interface}:0" >/dev/null 2>&1
fi
# upstream dhclient-script removes (ifconfig $interface 0 up) old adresses in PREINIT,
# but we sometimes (#125298) need (for iSCSI/nfs root to have a dhcp interface) to keep the existing ip
# flush_dev ${interface}
ip link set dev "${interface}" up
if [ -n "${DHCLIENT_DELAY}" ] && [ "${DHCLIENT_DELAY}" -gt 0 ]; then
# We need to give the kernel some time to get the interface up.
sleep "${DHCLIENT_DELAY}"
fi
exit_with_hooks 0
;;
PREINIT6)
# ensure interface is up
ip link set dev "${interface}" up
# Removing stale addresses from aborted clients shouldn't be needed
# since we've been adding addresses with lifetimes.
# Which means that kernel eventually removes them automatically.
# ip -6 addr flush dev "${interface}" scope global permanent
wait_for_link_local
exit_with_hooks 0
;;
BOUND|RENEW|REBIND|REBOOT)
if [ -z "${interface}" ] || [ -z "${new_ip_address}" ]; then
exit_with_hooks 2
fi
if arping -D -q -c2 -I "${interface}" "${new_ip_address}"; then
dhconfig
exit_with_hooks 0
else # DAD failed, i.e. address is already in use
ARP_REPLY=$(arping -D -c2 -I "${interface}" "${new_ip_address}" | grep reply | awk '{print toupper($5)}' | cut -d "[" -f2 | cut -d "]" -f1)
OUR_MACS=$(ip link show | grep link | awk '{print toupper($2)}' | uniq)
if [[ "${OUR_MACS}" = *"${ARP_REPLY}"* ]]; then
# the reply can come from our system, that's OK (#1116004#c33)
dhconfig
exit_with_hooks 0
else
exit_with_hooks 1
fi
fi
;;
BOUND6|RENEW6|REBIND6|DEPREF6)
dh6config
exit_with_hooks 0
;;
EXPIRE6|RELEASE6|STOP6)
if [ -z "${old_ip6_address}" ] || [ -z "${old_ip6_prefixlen}" ]; then
exit_with_hooks 2
fi
ip -6 addr del "${old_ip6_address}/${old_ip6_prefixlen}" \
dev "${interface}"
execute_client_side_configuration_scripts "restore"
if [ -x "${ETCDIR}/dhclient-${interface}-down-hooks" ]; then
. "${ETCDIR}/dhclient-${interface}-down-hooks"
elif [ -x ${ETCDIR}/dhclient-down-hooks ]; then
. ${ETCDIR}/dhclient-down-hooks
fi
exit_with_hooks 0
;;
EXPIRE|FAIL|RELEASE|STOP)
execute_client_side_configuration_scripts "restore"
if [ -x "${ETCDIR}/dhclient-${interface}-down-hooks" ]; then
. "${ETCDIR}/dhclient-${interface}-down-hooks"
elif [ -x ${ETCDIR}/dhclient-down-hooks ]; then
. ${ETCDIR}/dhclient-down-hooks
fi
if [ -n "${alias_ip_address}" ]; then
# Flush alias
ip -4 addr flush dev "${interface}" label "${interface}:0" >/dev/null 2>&1
fi
# upstream script sets interface down here,
# we only remove old ip address
#flush_dev ${interface}
remove_old_addr
if [ -n "${alias_ip_address}" ]; then
ip -4 addr replace "${alias_ip_address}/${alias_prefix}" broadcast "${alias_broadcast_address}" dev "${interface}" label "${interface}:0"
ip -4 route replace "${alias_ip_address}/32" dev "${interface}"
fi
exit_with_hooks 0
;;
TIMEOUT)
if [ -n "${new_routers}" ]; then
if [ -n "${alias_ip_address}" ]; then
ip -4 addr flush dev "${interface}" label "${interface}:0" >/dev/null 2>&1
fi
ip -4 addr replace "${new_ip_address}/${new_prefix}" \
broadcast "${new_broadcast_address}" dev "${interface}" \
valid_lft "${new_dhcp_lease_time}" preferred_lft "${new_dhcp_lease_time}"
set ${new_routers}
if ping -q -c 1 -w 10 -I "${interface}" "${1}"; then
dhconfig
exit_with_hooks 0
fi
#flush_dev ${interface}
remove_old_addr
exit_with_hooks 1
else
exit_with_hooks 1
fi
;;
*)
logmessage "unhandled state: ${reason}"
exit_with_hooks 1
;;
esac
exit_with_hooks 0

@ -0,0 +1,15 @@
[Unit]
Description=DHCPv4 Server Daemon
Documentation=man:dhcpd(8) man:dhcpd.conf(5)
Wants=network-online.target
After=network-online.target
After=time-sync.target
[Service]
Type=notify
EnvironmentFile=-/etc/sysconfig/dhcpd
ExecStart=/usr/sbin/dhcpd -f -cf /etc/dhcp/dhcpd.conf -user dhcpd -group dhcpd --no-pid $DHCPDARGS
StandardError=null
[Install]
WantedBy=multi-user.target

@ -0,0 +1,15 @@
[Unit]
Description=DHCPv6 Server Daemon
Documentation=man:dhcpd(8) man:dhcpd.conf(5)
Wants=network-online.target
After=network-online.target
After=time-sync.target
[Service]
Type=notify
EnvironmentFile=-/etc/sysconfig/dhcpd6
ExecStart=/usr/sbin/dhcpd -f -6 -cf /etc/dhcp/dhcpd6.conf -user dhcpd -group dhcpd --no-pid $DHCPDARGS
StandardError=null
[Install]
WantedBy=multi-user.target

@ -0,0 +1,13 @@
[Unit]
Description=DHCP Relay Agent Daemon
Documentation=man:dhcrelay(8)
Wants=network-online.target
After=network-online.target
[Service]
Type=notify
ExecStart=/usr/sbin/dhcrelay -d --no-pid
StandardError=null
[Install]
WantedBy=multi-user.target

@ -0,0 +1,155 @@
diff --git a/omapip/connection.c b/omapip/connection.c
index 014ff21..6800514 100644
--- a/omapip/connection.c
+++ b/omapip/connection.c
@@ -44,6 +44,9 @@ extern omapi_array_t *trace_listeners;
#endif
static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
+static isc_result_t ctring_from_attribute(omapi_object_t *obj, char *attr_name,
+ char **cstr);
+
OMAPI_OBJECT_ALLOC (omapi_connection,
omapi_connection_object_t, omapi_type_connection)
@@ -763,64 +766,41 @@ isc_result_t omapi_connection_reaper (omapi_object_t *h)
}
static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) {
- omapi_value_t *name = (omapi_value_t *)0;
- omapi_value_t *algorithm = (omapi_value_t *)0;
- omapi_value_t *key = (omapi_value_t *)0;
- char *name_str = NULL;
+ omapi_value_t *key = 0;
+ char *name_str = 0;
+ char *algorithm_str = 0;
isc_result_t status = ISC_R_SUCCESS;
- if (status == ISC_R_SUCCESS)
- status = omapi_get_value_str
- (a, (omapi_object_t *)0, "name", &name);
-
- if (status == ISC_R_SUCCESS)
- status = omapi_get_value_str
- (a, (omapi_object_t *)0, "algorithm", &algorithm);
-
- if (status == ISC_R_SUCCESS)
- status = omapi_get_value_str
- (a, (omapi_object_t *)0, "key", &key);
-
+ /* Get the key name as a C string. */
+ status = ctring_from_attribute(a, "name", &name_str);
if (status == ISC_R_SUCCESS) {
- if ((algorithm->value->type != omapi_datatype_data &&
- algorithm->value->type != omapi_datatype_string) ||
- strncasecmp((char *)algorithm->value->u.buffer.value,
- NS_TSIG_ALG_HMAC_MD5 ".",
- algorithm->value->u.buffer.len) != 0) {
- status = DHCP_R_INVALIDARG;
+ /* Get the algorithm name as a C string. */
+ status = ctring_from_attribute(a, "algorithm", &algorithm_str);
+ if (status == ISC_R_SUCCESS) {
+ /* Get the key secret value */
+ status = omapi_get_value_str(a, 0, "key", &key);
+ if (status == ISC_R_SUCCESS) {
+ /* Now let's try and create the key */
+ status = isclib_make_dst_key(
+ name_str,
+ algorithm_str,
+ key->value->u.buffer.value,
+ key->value->u.buffer.len,
+ dst_key);
+
+ if (*dst_key == NULL) {
+ status = ISC_R_NOMEMORY;
+ }
+ }
}
}
- if (status == ISC_R_SUCCESS) {
- name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL);
- if (!name_str)
- status = ISC_R_NOMEMORY;
- }
-
- if (status == ISC_R_SUCCESS) {
- memcpy (name_str,
- name -> value -> u.buffer.value,
- name -> value -> u.buffer.len);
- name_str [name -> value -> u.buffer.len] = 0;
-
- status = isclib_make_dst_key(name_str,
- DHCP_HMAC_MD5_NAME,
- key->value->u.buffer.value,
- key->value->u.buffer.len,
- dst_key);
-
- if (*dst_key == NULL)
- status = ISC_R_NOMEMORY;
- }
-
if (name_str)
dfree (name_str, MDL);
+ if (algorithm_str)
+ dfree (algorithm_str, MDL);
if (key)
omapi_value_dereference (&key, MDL);
- if (algorithm)
- omapi_value_dereference (&algorithm, MDL);
- if (name)
- omapi_value_dereference (&name, MDL);
return status;
}
@@ -1103,3 +1083,50 @@ isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
m -> inner);
return ISC_R_SUCCESS;
}
+
+/* @brief Fetches the value of an attribute in an object as an allocated
+ * C string
+ *
+ * @param obj ompapi object containing the desire attribute
+ * @param attr_name name of the desired attribute
+ * @param[out] cstr pointer in which to place the allocated C string's address
+ *
+ * Caller is responsible for freeing (via dfree) the allocated string.
+ *
+ * @return ISC_R_SUCCESS if successful, otherwise indicates the type of failure
+*/
+static isc_result_t ctring_from_attribute(omapi_object_t *obj, char *attr_name,
+ char **cstr) {
+ isc_result_t status = ISC_R_SUCCESS;
+ omapi_value_t *attr = 0;
+
+ /* Find the attribute in the object. */
+ status = omapi_get_value_str(obj, (omapi_object_t *)0, attr_name,
+ &attr);
+ if (status != ISC_R_SUCCESS) {
+ return (status);
+ }
+
+ /* Got it, let's make sure it's either data or string type. */
+ if (attr->value->type != omapi_datatype_data &&
+ attr->value->type != omapi_datatype_string) {
+ return (DHCP_R_INVALIDARG);
+ }
+
+ /* Make a C string from the attribute value. */
+ *cstr = dmalloc (attr->value->u.buffer.len + 1, MDL);
+ if (!(*cstr)) {
+ status = ISC_R_NOMEMORY;
+ } else {
+ memcpy (*cstr, attr->value->u.buffer.value,
+ attr->value->u.buffer.len);
+ (*cstr)[attr->value->u.buffer.len] = 0;
+ }
+
+ /* Get rid of the attribute reference */
+ if (attr) {
+ omapi_value_dereference (&attr, MDL);
+ }
+
+ return (status);
+}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save