diff --git a/.dhcp.metadata b/.dhcp.metadata new file mode 100644 index 0000000..9b87ec1 --- /dev/null +++ b/.dhcp.metadata @@ -0,0 +1 @@ +e4338f80bd2118ba1578e4bd3c2c154ec9c12ce0 SOURCES/dhcp-4.4.2b1.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ff94719 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/dhcp-4.4.2b1.tar.gz diff --git a/SOURCES/0001-change-bug-url.patch b/SOURCES/0001-change-bug-url.patch new file mode 100644 index 0000000..b6afa57 --- /dev/null +++ b/SOURCES/0001-change-bug-url.patch @@ -0,0 +1,78 @@ +From 23dfbc560028bf7429196db1a3826f8b80c19d3e Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0002-additional-dhclient-options.patch b/SOURCES/0002-additional-dhclient-options.patch new file mode 100644 index 0000000..d700c00 --- /dev/null +++ b/SOURCES/0002-additional-dhclient-options.patch @@ -0,0 +1,468 @@ +From a26161b0fd45cdbeed3038ac63ff04e3b727248f Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + #include + ++/* ++ * 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 ] [-B]\n" \ ++" [-H | -F ] [--timeout ]\n" \ ++" [-V ]\n" \ ++" [--request-options ]" ++ + #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 and -F 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 argument can be specified"); ++ exit(1); ++ } ++ ++ if (dhcp_host_name_arg != NULL) { ++ log_error("The -F and -H 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 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 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 + diff --git a/SOURCES/0003-Handle-releasing-interfaces-requested-by-sbin-ifup.patch b/SOURCES/0003-Handle-releasing-interfaces-requested-by-sbin-ifup.patch new file mode 100644 index 0000000..2953c0f --- /dev/null +++ b/SOURCES/0003-Handle-releasing-interfaces-requested-by-sbin-ifup.patch @@ -0,0 +1,99 @@ +From af504e99abde04b881768d18eaa0054b36b16303 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0004-Support-unicast-BOOTP-for-IBM-pSeries-systems-and-ma.patch b/SOURCES/0004-Support-unicast-BOOTP-for-IBM-pSeries-systems-and-ma.patch new file mode 100644 index 0000000..7f414a3 --- /dev/null +++ b/SOURCES/0004-Support-unicast-BOOTP-for-IBM-pSeries-systems-and-ma.patch @@ -0,0 +1,118 @@ +From 7e8cc8388ac31c5c2b1a423c6b2da0491b19f6f9 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0005-Change-default-requested-options.patch b/SOURCES/0005-Change-default-requested-options.patch new file mode 100644 index 0000000..34ff7b5 --- /dev/null +++ b/SOURCES/0005-Change-default-requested-options.patch @@ -0,0 +1,60 @@ +From a2a3554ff9e05d1a8e2c8aa843f1b6a33fce87e3 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0006-Various-man-page-only-fixes.patch b/SOURCES/0006-Various-man-page-only-fixes.patch new file mode 100644 index 0000000..a98783c --- /dev/null +++ b/SOURCES/0006-Various-man-page-only-fixes.patch @@ -0,0 +1,168 @@ +From 846779467f7393b19e8d206405116e1e26e16efc Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0007-Change-paths-to-conform-to-our-standards.patch b/SOURCES/0007-Change-paths-to-conform-to-our-standards.patch new file mode 100644 index 0000000..87c4f8c --- /dev/null +++ b/SOURCES/0007-Change-paths-to-conform-to-our-standards.patch @@ -0,0 +1,54 @@ +From ac65289663532db0bc1de449ca2a0eb4c8c2ca6f Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0008-Make-sure-all-open-file-descriptors-are-closed-on-ex.patch b/SOURCES/0008-Make-sure-all-open-file-descriptors-are-closed-on-ex.patch new file mode 100644 index 0000000..8294563 --- /dev/null +++ b/SOURCES/0008-Make-sure-all-open-file-descriptors-are-closed-on-ex.patch @@ -0,0 +1,367 @@ +From d2da34706f140101c34f6a9806c258411806a939 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0009-Fix-garbage-in-format-string-error.patch b/SOURCES/0009-Fix-garbage-in-format-string-error.patch new file mode 100644 index 0000000..f9d81ab --- /dev/null +++ b/SOURCES/0009-Fix-garbage-in-format-string-error.patch @@ -0,0 +1,27 @@ +From a0a2186ce52a31357d4eb3c32d7d6887e4603814 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0010-Handle-null-timeout.patch b/SOURCES/0010-Handle-null-timeout.patch new file mode 100644 index 0000000..2b6e49b --- /dev/null +++ b/SOURCES/0010-Handle-null-timeout.patch @@ -0,0 +1,32 @@ +From ed7610cdb2e8ebdbaee618e477879e7e008d4f29 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0011-Drop-unnecessary-capabilities.patch b/SOURCES/0011-Drop-unnecessary-capabilities.patch new file mode 100644 index 0000000..4277baf --- /dev/null +++ b/SOURCES/0011-Drop-unnecessary-capabilities.patch @@ -0,0 +1,278 @@ +From 3b37f4b7bb3a17f8bd655be919915a1912062ea6 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + #include + ++#ifdef HAVE_LIBCAP_NG ++#include ++#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 + #include + ++#ifdef HAVE_LIBCAP_NG ++# include ++ 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 + diff --git a/SOURCES/0012-RFC-3442-Classless-Static-Route-Option-for-DHCPv4-51.patch b/SOURCES/0012-RFC-3442-Classless-Static-Route-Option-for-DHCPv4-51.patch new file mode 100644 index 0000000..866527c --- /dev/null +++ b/SOURCES/0012-RFC-3442-Classless-Static-Route-Option-for-DHCPv4-51.patch @@ -0,0 +1,439 @@ +From 01b1dcfef129a4eccfaf0f63a216774019f82dca Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 ""; ++ } ++ 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 ""; ++ } ++ ++ 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 + diff --git a/SOURCES/0013-DHCPv6-over-PPP-support-626514.patch b/SOURCES/0013-DHCPv6-over-PPP-support-626514.patch new file mode 100644 index 0000000..5e0a6ba --- /dev/null +++ b/SOURCES/0013-DHCPv6-over-PPP-support-626514.patch @@ -0,0 +1,176 @@ +From 234747fbfd6c6429619ba843713d5b39fb4a513d Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0014-IPoIB-support-660681.patch b/SOURCES/0014-IPoIB-support-660681.patch new file mode 100644 index 0000000..3d6d316 --- /dev/null +++ b/SOURCES/0014-IPoIB-support-660681.patch @@ -0,0 +1,629 @@ +From 042082b4410f158ec86ca8478689b34bc12518e6 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + #include + #include ++#include ++ ++/* 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 + diff --git a/SOURCES/0015-Add-GUID-DUID-to-dhcpd-logs-1064416.patch b/SOURCES/0015-Add-GUID-DUID-to-dhcpd-logs-1064416.patch new file mode 100644 index 0000000..1f88d7d --- /dev/null +++ b/SOURCES/0015-Add-GUID-DUID-to-dhcpd-logs-1064416.patch @@ -0,0 +1,332 @@ +From 3d3e442ed1316930a5360e4d5a56b46a42a29419 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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) + : ""), + 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) + : "")), +@@ -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) + : "")), +@@ -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) + : "")), +@@ -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) + : "")), +@@ -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) : + ""); + 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 + diff --git a/SOURCES/0016-Turn-on-creating-sending-of-DUID.patch b/SOURCES/0016-Turn-on-creating-sending-of-DUID.patch new file mode 100644 index 0000000..bafffb5 --- /dev/null +++ b/SOURCES/0016-Turn-on-creating-sending-of-DUID.patch @@ -0,0 +1,126 @@ +From 2f6b827e89305adcff45288c632785ac054adb8e Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0017-Send-unicast-request-release-via-correct-interface.patch b/SOURCES/0017-Send-unicast-request-release-via-correct-interface.patch new file mode 100644 index 0000000..26c8b96 --- /dev/null +++ b/SOURCES/0017-Send-unicast-request-release-via-correct-interface.patch @@ -0,0 +1,77 @@ +From 193c4d7631fd623efa601f52fdab6018bf8be771 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0018-No-subnet-declaration-for-iface-should-be-info-not-e.patch b/SOURCES/0018-No-subnet-declaration-for-iface-should-be-info-not-e.patch new file mode 100644 index 0000000..2ff4030 --- /dev/null +++ b/SOURCES/0018-No-subnet-declaration-for-iface-should-be-info-not-e.patch @@ -0,0 +1,63 @@ +From 2277d041692b8ebdf6b86d41e3a0bc0381cd1e47 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +Date: Thu, 21 Feb 2019 10:40:51 +0100 +Subject: [PATCH 18/26] No subnet declaration for ' 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 + diff --git a/SOURCES/0019-dhclient-write-DUID_LLT-even-in-stateless-mode-11563.patch b/SOURCES/0019-dhclient-write-DUID_LLT-even-in-stateless-mode-11563.patch new file mode 100644 index 0000000..3405ea1 --- /dev/null +++ b/SOURCES/0019-dhclient-write-DUID_LLT-even-in-stateless-mode-11563.patch @@ -0,0 +1,29 @@ +From 6ea56e988df1da51f7d0bdd8984b38e40102c17b Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0020-Discover-all-hwaddress-for-xid-uniqueness.patch b/SOURCES/0020-Discover-all-hwaddress-for-xid-uniqueness.patch new file mode 100644 index 0000000..c838d7a --- /dev/null +++ b/SOURCES/0020-Discover-all-hwaddress-for-xid-uniqueness.patch @@ -0,0 +1,101 @@ +From 01ce61b8a0331a2f068ca2191bfb897b505c1b9d Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0021-Load-leases-DB-in-non-replay-mode-only.patch b/SOURCES/0021-Load-leases-DB-in-non-replay-mode-only.patch new file mode 100644 index 0000000..d398918 --- /dev/null +++ b/SOURCES/0021-Load-leases-DB-in-non-replay-mode-only.patch @@ -0,0 +1,50 @@ +commit 50c2b3ba8ce030a47b55dd707bb8a6ab20444a05 +Author: Pavel Zhukov +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; + } diff --git a/SOURCES/0022-dhclient-make-sure-link-local-address-is-ready-in-st.patch b/SOURCES/0022-dhclient-make-sure-link-local-address-is-ready-in-st.patch new file mode 100644 index 0000000..85ea650 --- /dev/null +++ b/SOURCES/0022-dhclient-make-sure-link-local-address-is-ready-in-st.patch @@ -0,0 +1,80 @@ +From 9975d198a2c02e32c31c3e0f43d2aa79dfa7f508 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0023-option-97-pxe-client-id.patch b/SOURCES/0023-option-97-pxe-client-id.patch new file mode 100644 index 0000000..6cc4328 --- /dev/null +++ b/SOURCES/0023-option-97-pxe-client-id.patch @@ -0,0 +1,247 @@ +From 6fd7894ea57791c8eee16c21d19da34b909e016e Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0024-Detect-system-time-changes.patch b/SOURCES/0024-Detect-system-time-changes.patch new file mode 100644 index 0000000..cf38d0d --- /dev/null +++ b/SOURCES/0024-Detect-system-time-changes.patch @@ -0,0 +1,93 @@ +From 41c6032ace65119e6a400365f7e90283c930afd4 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0025-bind-Detect-system-time-changes.patch b/SOURCES/0025-bind-Detect-system-time-changes.patch new file mode 100644 index 0000000..80191b2 --- /dev/null +++ b/SOURCES/0025-bind-Detect-system-time-changes.patch @@ -0,0 +1,197 @@ +From ef4f5e80d8a1ea1507829ea6f5214f276478f475 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0026-Add-dhclient-5-B-option-description.patch b/SOURCES/0026-Add-dhclient-5-B-option-description.patch new file mode 100644 index 0000000..7ddfacf --- /dev/null +++ b/SOURCES/0026-Add-dhclient-5-B-option-description.patch @@ -0,0 +1,24 @@ +commit 6acfd3125546a0e5db8fae8a9964cd2f88bf68c0 +Author: Pavel Zhukov +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 diff --git a/SOURCES/0027-Add-missed-sd-notify-patch-to-manage-dhcpd-with-syst.patch b/SOURCES/0027-Add-missed-sd-notify-patch-to-manage-dhcpd-with-syst.patch new file mode 100644 index 0000000..cde51de --- /dev/null +++ b/SOURCES/0027-Add-missed-sd-notify-patch-to-manage-dhcpd-with-syst.patch @@ -0,0 +1,97 @@ +From 8d974fd1f667e1b957ad4092fe66a8bb94f5f8fd Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 ++#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 ++#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 + diff --git a/SOURCES/0028-Fix-for-CVE-2021-25217.patch b/SOURCES/0028-Fix-for-CVE-2021-25217.patch new file mode 100644 index 0000000..7f9dad9 --- /dev/null +++ b/SOURCES/0028-Fix-for-CVE-2021-25217.patch @@ -0,0 +1,34 @@ +From 02b4ae1953d39f1b6c3f0e63aefb72114039ab50 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/0029-Use-system-getaddrinfo-for-dhcp.patch b/SOURCES/0029-Use-system-getaddrinfo-for-dhcp.patch new file mode 100644 index 0000000..24cbb6b --- /dev/null +++ b/SOURCES/0029-Use-system-getaddrinfo-for-dhcp.patch @@ -0,0 +1,118 @@ +From 019021caa791c254a319c71b4f634142dc14b37d Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +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 + diff --git a/SOURCES/11-dhclient b/SOURCES/11-dhclient new file mode 100644 index 0000000..8bd0c75 --- /dev/null +++ b/SOURCES/11-dhclient @@ -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 diff --git a/SOURCES/56dhclient b/SOURCES/56dhclient new file mode 100644 index 0000000..7f185f1 --- /dev/null +++ b/SOURCES/56dhclient @@ -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 diff --git a/SOURCES/README.dhclient.d b/SOURCES/README.dhclient.d new file mode 100644 index 0000000..6899aaa --- /dev/null +++ b/SOURCES/README.dhclient.d @@ -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 diff --git a/SOURCES/dhclient-script b/SOURCES/dhclient-script new file mode 100644 index 0000000..5f58112 --- /dev/null +++ b/SOURCES/dhclient-script @@ -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 . +# +# Author(s): David Cantrell +# Jiri Popelka +# +# ---------- +# 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 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 (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 -> + # 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 diff --git a/SOURCES/dhcpd.service b/SOURCES/dhcpd.service new file mode 100644 index 0000000..7363d7d --- /dev/null +++ b/SOURCES/dhcpd.service @@ -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 diff --git a/SOURCES/dhcpd6.service b/SOURCES/dhcpd6.service new file mode 100644 index 0000000..ff844c0 --- /dev/null +++ b/SOURCES/dhcpd6.service @@ -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 diff --git a/SOURCES/dhcrelay.service b/SOURCES/dhcrelay.service new file mode 100644 index 0000000..43a0ca3 --- /dev/null +++ b/SOURCES/dhcrelay.service @@ -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 diff --git a/SPECS/dhcp.spec b/SPECS/dhcp.spec new file mode 100644 index 0000000..7066a4a --- /dev/null +++ b/SPECS/dhcp.spec @@ -0,0 +1,1882 @@ +# SystemTap support is disabled by default +%{!?sdt:%global sdt 0} + +#http://lists.fedoraproject.org/pipermail/devel/2011-August/155358.html +%global _hardened_build 1 + +# Where dhcp configuration files are stored +%global dhcpconfdir %{_sysconfdir}/dhcp + + +%global prever b1 +#global patchver P1 +%global DHCPVERSION %{version}%{?prever}%{?patchver:-%{patchver}} + +Summary: Dynamic host configuration protocol software +Name: dhcp +Version: 4.4.2 +Release: 15.b1%{?dist} + +# NEVER CHANGE THE EPOCH on this package. The previous maintainer (prior to +# dcantrell maintaining the package) made incorrect use of the epoch and +# that's why it is at 12 now. It should have never been used, but it was. +# So we are stuck with it. +Epoch: 12 +License: ISC +Url: https://www.isc.org/dhcp/ +Source0: ftp://ftp.isc.org/isc/dhcp/%{DHCPVERSION}/dhcp-%{DHCPVERSION}.tar.gz +Source1: dhclient-script +Source2: README.dhclient.d +Source3: 11-dhclient +Source5: 56dhclient +Source6: dhcpd.service +Source7: dhcpd6.service +Source8: dhcrelay.service + +Patch1 : 0001-change-bug-url.patch +Patch2 : 0002-additional-dhclient-options.patch +Patch3 : 0003-Handle-releasing-interfaces-requested-by-sbin-ifup.patch +Patch4 : 0004-Support-unicast-BOOTP-for-IBM-pSeries-systems-and-ma.patch +Patch5 : 0005-Change-default-requested-options.patch +Patch6 : 0006-Various-man-page-only-fixes.patch +Patch7 : 0007-Change-paths-to-conform-to-our-standards.patch +Patch8 : 0008-Make-sure-all-open-file-descriptors-are-closed-on-ex.patch +Patch9 : 0009-Fix-garbage-in-format-string-error.patch +Patch10 : 0010-Handle-null-timeout.patch +Patch11 : 0011-Drop-unnecessary-capabilities.patch +Patch12 : 0012-RFC-3442-Classless-Static-Route-Option-for-DHCPv4-51.patch +Patch13 : 0013-DHCPv6-over-PPP-support-626514.patch +Patch14 : 0014-IPoIB-support-660681.patch +Patch15 : 0015-Add-GUID-DUID-to-dhcpd-logs-1064416.patch +Patch16 : 0016-Turn-on-creating-sending-of-DUID.patch +Patch17 : 0017-Send-unicast-request-release-via-correct-interface.patch +Patch18 : 0018-No-subnet-declaration-for-iface-should-be-info-not-e.patch +Patch19 : 0019-dhclient-write-DUID_LLT-even-in-stateless-mode-11563.patch +Patch20 : 0020-Discover-all-hwaddress-for-xid-uniqueness.patch +Patch21 : 0021-Load-leases-DB-in-non-replay-mode-only.patch +Patch22 : 0022-dhclient-make-sure-link-local-address-is-ready-in-st.patch +Patch23 : 0023-option-97-pxe-client-id.patch +Patch24 : 0024-Detect-system-time-changes.patch +Patch25 : 0025-bind-Detect-system-time-changes.patch +Patch26 : 0026-Add-dhclient-5-B-option-description.patch +Patch27: 0027-Add-missed-sd-notify-patch-to-manage-dhcpd-with-syst.patch +Patch28: 0028-Fix-for-CVE-2021-25217.patch +Patch29: 0029-Use-system-getaddrinfo-for-dhcp.patch + + +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: make +BuildRequires: libtool +BuildRequires: openldap-devel +# --with-ldap-gssapi +BuildRequires: krb5-devel +BuildRequires: libcap-ng-devel +# https://fedorahosted.org/fpc/ticket/502#comment:3 +BuildRequires: systemd systemd-devel +# dhcp-sd_notify.patch +BuildRequires: pkgconfig(libsystemd) +%if ! 0%{?_module_build} +BuildRequires: doxygen +%endif +%if %{sdt} +BuildRequires: systemtap-sdt-devel +%global tapsetdir /usr/share/systemtap/tapset +%endif + +# In _docdir we ship some perl scripts and module from contrib subdirectory. +# Because nothing under _docdir is allowed to "require" anything, +# prevent _docdir from being scanned. (#674058) +%filter_requires_in %{_docdir} +%{filter_setup} + +%description +DHCP (Dynamic Host Configuration Protocol) + +%package server +Summary: Provides the ISC DHCP server +Requires: %{name}-common = %{epoch}:%{version}-%{release} +Requires(pre): shadow-utils +Requires(post): coreutils grep sed +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +%description server +DHCP (Dynamic Host Configuration Protocol) is a protocol which allows +individual devices on an IP network to get their own network +configuration information (IP address, subnetmask, broadcast address, +etc.) from a DHCP server. The overall purpose of DHCP is to make it +easier to administer a large network. + +This package provides the ISC DHCP server. + +%package relay +Summary: Provides the ISC DHCP relay agent +Requires: %{name}-common = %{epoch}:%{version}-%{release} +Requires(post): grep sed +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +%description relay +DHCP (Dynamic Host Configuration Protocol) is a protocol which allows +individual devices on an IP network to get their own network +configuration information (IP address, subnetmask, broadcast address, +etc.) from a DHCP server. The overall purpose of DHCP is to make it +easier to administer a large network. + +This package provides the ISC DHCP relay agent. + + +%package client +Summary: Provides the ISC DHCP client daemon and dhclient-script +Provides: dhclient = %{epoch}:%{version}-%{release} +Obsoletes: dhclient < %{epoch}:%{version}-%{release} +# dhclient-script requires: +Requires: coreutils gawk grep ipcalc iproute iputils sed systemd +Requires: %{name}-common = %{epoch}:%{version}-%{release} +# Old NetworkManager expects the dispatcher scripts in a different place +Conflicts: NetworkManager < 1.20 + +%description client +DHCP (Dynamic Host Configuration Protocol) is a protocol which allows +individual devices on an IP network to get their own network +configuration information (IP address, subnetmask, broadcast address, +etc.) from a DHCP server. The overall purpose of DHCP is to make it +easier to administer a large network. + +This package provides the ISC DHCP client. + +%package common +Summary: Common files used by ISC dhcp client, server and relay agent +BuildArch: noarch +Obsoletes: dhcp-libs < %{epoch}:%{version} + + + +%description common +DHCP (Dynamic Host Configuration Protocol) is a protocol which allows +individual devices on an IP network to get their own network +configuration information (IP address, subnetmask, broadcast address, +etc.) from a DHCP server. The overall purpose of DHCP is to make it +easier to administer a large network. + +This package provides common files used by dhcp and dhclient package. + +%package libs-static +Summary: Shared libraries used by ISC dhcp client and server +Provides: %{name}-libs%{?_isa} = %{epoch}:%{version}-%{release} +Provides: %{name}-libs = %{epoch}:%{version}-%{release} +Provides: bundled(bind-export-libs) +Provides: bundled(bind) + +%description libs-static +This package contains shared libraries used by ISC dhcp client and server + + +%package devel +Summary: Development headers and libraries for interfacing to the DHCP server +Requires: %{name}-libs%{?_isa} = %{epoch}:%{version}-%{release} + +%description devel +Header files and API documentation for using the ISC DHCP libraries. The +libdhcpctl and libomapi static libraries are also included in this package. + +%if ! 0%{?_module_build} +%package devel-doc +Summary: Developer's Guide for ISC DHCP +Requires: %{name}-libs = %{epoch}:%{version}-%{release} +BuildArch: noarch + +%description devel-doc +This documentation is intended for developers, contributors and other +programmers that are interested in internal operation of the code. +This package contains doxygen-generated documentation. +%endif + +%prep +%setup -n dhcp-%{DHCPVERSION} +pushd bind +tar -xvf bind.tar.gz +ln -s bind-9* bind +popd +%autopatch -p1 + +# Update paths in all man pages +for page in client/dhclient.conf.5 client/dhclient.leases.5 \ + client/dhclient-script.8 client/dhclient.8 ; do + sed -i -e 's|CLIENTBINDIR|%{_sbindir}|g' \ + -e 's|RUNDIR|%{_localstatedir}/run|g' \ + -e 's|DBDIR|%{_localstatedir}/lib/dhclient|g' \ + -e 's|ETCDIR|%{dhcpconfdir}|g' $page +done + +for page in server/dhcpd.conf.5 server/dhcpd.leases.5 server/dhcpd.8 ; do + sed -i -e 's|CLIENTBINDIR|%{_sbindir}|g' \ + -e 's|RUNDIR|%{_localstatedir}/run|g' \ + -e 's|DBDIR|%{_localstatedir}/lib/dhcpd|g' \ + -e 's|ETCDIR|%{dhcpconfdir}|g' $page +done + +sed -i -e 's|/var/db/|%{_localstatedir}/lib/dhcpd/|g' contrib/dhcp-lease-list.pl + +## FIXME drop unused bind components + +%build +#libtoolize --copy --force +autoreconf --verbose --force --install + +CFLAGS="%{optflags} -fno-strict-aliasing -fcommon" \ +%configure \ + --with-srv-lease-file=%{_localstatedir}/lib/dhcpd/dhcpd.leases \ + --with-srv6-lease-file=%{_localstatedir}/lib/dhcpd/dhcpd6.leases \ + --with-cli-lease-file=%{_localstatedir}/lib/dhclient/dhclient.leases \ + --with-cli6-lease-file=%{_localstatedir}/lib/dhclient/dhclient6.leases \ + --with-srv-pid-file=%{_localstatedir}/run/dhcpd.pid \ + --with-srv6-pid-file=%{_localstatedir}/run/dhcpd6.pid \ + --with-cli-pid-file=%{_localstatedir}/run/dhclient.pid \ + --with-cli6-pid-file=%{_localstatedir}/run/dhclient6.pid \ + --with-relay-pid-file=%{_localstatedir}/run/dhcrelay.pid \ + --with-ldap \ + --with-ldapcrypto \ + --with-ldap-gssapi \ + --enable-log-pid \ +%if %{sdt} + --enable-systemtap \ + --with-tapset-install-dir=%{tapsetdir} \ +%endif + --enable-paranoia --enable-early-chroot \ + --enable-binary-leases \ + --with-systemd +make -j1 + +%if ! 0%{?_module_build} +pushd doc +make %{?_smp_mflags} devel +popd +%endif + +%install +make DESTDIR=%{buildroot} install %{?_smp_mflags} + +# We don't want example conf files in /etc +rm -f %{buildroot}%{_sysconfdir}/dhclient.conf.example +rm -f %{buildroot}%{_sysconfdir}/dhcpd.conf.example + +# dhclient-script +install -D -p -m 0755 %{SOURCE1} %{buildroot}%{_sbindir}/dhclient-script + +# README.dhclient.d +install -p -m 0644 %{SOURCE2} . + +# Empty directory for dhclient.d scripts +mkdir -p %{buildroot}%{dhcpconfdir}/dhclient.d + +# NetworkManager dispatcher script +mkdir -p %{buildroot}%{_prefix}/lib/NetworkManager/dispatcher.d +install -p -m 0755 %{SOURCE3} %{buildroot}%{_prefix}/lib/NetworkManager/dispatcher.d + +# pm-utils script to handle suspend/resume and dhclient leases +install -D -p -m 0755 %{SOURCE5} %{buildroot}%{_libdir}/pm-utils/sleep.d/56dhclient + +# systemd unit files +mkdir -p %{buildroot}%{_unitdir} +install -m 644 %{SOURCE6} %{buildroot}%{_unitdir} +install -m 644 %{SOURCE7} %{buildroot}%{_unitdir} +install -m 644 %{SOURCE8} %{buildroot}%{_unitdir} + +# Start empty lease databases +mkdir -p %{buildroot}%{_localstatedir}/lib/dhcpd/ +touch %{buildroot}%{_localstatedir}/lib/dhcpd/dhcpd.leases +touch %{buildroot}%{_localstatedir}/lib/dhcpd/dhcpd6.leases +mkdir -p %{buildroot}%{_localstatedir}/lib/dhclient/ + +# default sysconfig file for dhcpd +mkdir -p %{buildroot}%{_sysconfdir}/sysconfig +cat < %{buildroot}%{_sysconfdir}/sysconfig/dhcpd +# WARNING: This file is NOT used anymore. + +# If you are here to restrict what interfaces should dhcpd listen on, +# be aware that dhcpd listens *only* on interfaces for which it finds subnet +# declaration in dhcpd.conf. It means that explicitly enumerating interfaces +# also on command line should not be required in most cases. + +# If you still insist on adding some command line options, +# copy dhcpd.service from /lib/systemd/system to /etc/systemd/system and modify +# it there. +# https://fedoraproject.org/wiki/Systemd#How_do_I_customize_a_unit_file.2F_add_a_custom_unit_file.3F + +# example: +# $ cp /usr/lib/systemd/system/dhcpd.service /etc/systemd/system/ +# $ vi /etc/systemd/system/dhcpd.service +# $ ExecStart=/usr/sbin/dhcpd -f -cf /etc/dhcp/dhcpd.conf -user dhcpd -group dhcpd --no-pid +# $ systemctl --system daemon-reload +# $ systemctl restart dhcpd.service +EOF + +# Copy sample conf files into position (called by doc macro) +cp -p doc/examples/dhclient-dhcpv6.conf client/dhclient6.conf.example +cp -p doc/examples/dhcpd-dhcpv6.conf server/dhcpd6.conf.example + +cat << EOF > client/dhclient-enter-hooks +#!/bin/bash + +# For dhclient/dhclient-script debugging. +# Copy this into /etc/dhcp/ and make it executable. +# Run 'dhclient -d ' to see info passed from dhclient to dhclient-script. +# See also HOOKS section in dhclient-script(8) man page. + +echo "interface: ${interface}" +echo "reason: ${reason}" + +( set -o posix ; set ) | grep "old_" +( set -o posix ; set ) | grep "new_" +( set -o posix ; set ) | grep "alias_" +( set -o posix ; set ) | grep "requested_" +EOF + +# Install default (empty) dhcpd.conf: +mkdir -p %{buildroot}%{dhcpconfdir} +cat << EOF > %{buildroot}%{dhcpconfdir}/dhcpd.conf +# +# DHCP Server Configuration file. +# see /usr/share/doc/dhcp-server/dhcpd.conf.example +# see dhcpd.conf(5) man page +# +EOF + +# Install default (empty) dhcpd6.conf: +cat << EOF > %{buildroot}%{dhcpconfdir}/dhcpd6.conf +# +# DHCPv6 Server Configuration file. +# see /usr/share/doc/dhcp-server/dhcpd6.conf.example +# see dhcpd.conf(5) man page +# +EOF + +# Install dhcp.schema for LDAP configuration +install -D -p -m 0644 contrib/ldap/dhcp.schema %{buildroot}%{_sysconfdir}/openldap/schema/dhcp.schema + +# Don't package libtool *.la files +find %{buildroot} -type f -name "*.la" -delete -print + +%pre server +# /usr/share/doc/setup/uidgid +%global gid_uid 177 +getent group dhcpd >/dev/null || groupadd --force --gid %{gid_uid} --system dhcpd +if ! getent passwd dhcpd >/dev/null ; then + if ! getent passwd %{gid_uid} >/dev/null ; then + useradd --system --uid %{gid_uid} --gid dhcpd --home / --shell /sbin/nologin --comment "DHCP server" dhcpd + else + useradd --system --gid dhcpd --home / --shell /sbin/nologin --comment "DHCP server" dhcpd + fi +fi +exit 0 + +%post server +# Initial installation +%systemd_post dhcpd.service dhcpd6.service + + +for servicename in dhcpd dhcpd6; do + etcservicefile=%{_sysconfdir}/systemd/system/${servicename}.service + if [ -f ${etcservicefile} ]; then + grep -q Type= ${etcservicefile} || sed -i '/\[Service\]/a Type=notify' ${etcservicefile} + sed -i 's/After=network.target/Wants=network-online.target\nAfter=network-online.target/' ${etcservicefile} + fi +done +exit 0 + +%post relay +# Initial installation +%systemd_post dhcrelay.service + +for servicename in dhcrelay; do + etcservicefile=%{_sysconfdir}/systemd/system/${servicename}.service + if [ -f ${etcservicefile} ]; then + grep -q Type= ${etcservicefile} || sed -i '/\[Service\]/a Type=notify' ${etcservicefile} + sed -i 's/After=network.target/Wants=network-online.target\nAfter=network-online.target/' ${etcservicefile} + fi +done +exit 0 + +%preun server +# Package removal, not upgrade +%systemd_preun dhcpd.service dhcpd6.service + +%preun relay +# Package removal, not upgrade +%systemd_preun dhcrelay.service + + +%postun server +# Package upgrade, not uninstall +%systemd_postun_with_restart dhcpd.service dhcpd6.service + +%postun relay +# Package upgrade, not uninstall +%systemd_postun_with_restart dhcrelay.service + + +%triggerun -- dhcp +# convert DHC*ARGS from /etc/sysconfig/dhc* to /etc/systemd/system/dhc*.service +for servicename in dhcpd dhcpd6 dhcrelay; do + if [ -f %{_sysconfdir}/sysconfig/${servicename} ]; then + # get DHCPDARGS/DHCRELAYARGS value from /etc/sysconfig/${servicename} + source %{_sysconfdir}/sysconfig/${servicename} + if [ "${servicename}" == "dhcrelay" ]; then + args=$DHCRELAYARGS + else + args=$DHCPDARGS + fi + # value is non-empty (i.e. user modified) and there isn't a service unit yet + if [ -n "${args}" -a ! -f %{_sysconfdir}/systemd/system/${servicename}.service ]; then + # in $args replace / with \/ otherwise the next sed won't take it + args=$(echo $args | sed 's/\//\\\//'g) + # add $args to the end of ExecStart line + sed -r -e "/ExecStart=/ s/$/ ${args}/" \ + < %{_unitdir}/${servicename}.service \ + > %{_sysconfdir}/systemd/system/${servicename}.service + fi + fi +done + +%files server +%doc server/dhcpd.conf.example server/dhcpd6.conf.example +%doc contrib/ldap/ contrib/dhcp-lease-list.pl +%attr(0750,root,root) %dir %{dhcpconfdir} +%attr(0755,dhcpd,dhcpd) %dir %{_localstatedir}/lib/dhcpd +%attr(0644,dhcpd,dhcpd) %verify(mode) %config(noreplace) %{_localstatedir}/lib/dhcpd/dhcpd.leases +%attr(0644,dhcpd,dhcpd) %verify(mode) %config(noreplace) %{_localstatedir}/lib/dhcpd/dhcpd6.leases +%config(noreplace) %{_sysconfdir}/sysconfig/dhcpd +%config(noreplace) %{dhcpconfdir}/dhcpd.conf +%config(noreplace) %{dhcpconfdir}/dhcpd6.conf +%dir %{_sysconfdir}/openldap/schema +%config(noreplace) %{_sysconfdir}/openldap/schema/dhcp.schema +%attr(0644,root,root) %{_unitdir}/dhcpd.service +%attr(0644,root,root) %{_unitdir}/dhcpd6.service +%{_sbindir}/dhcpd +%{_bindir}/omshell +%attr(0644,root,root) %{_mandir}/man1/omshell.1.gz +%attr(0644,root,root) %{_mandir}/man5/dhcpd.conf.5.gz +%attr(0644,root,root) %{_mandir}/man5/dhcpd.leases.5.gz +%attr(0644,root,root) %{_mandir}/man8/dhcpd.8.gz +%if %{sdt} +%{tapsetdir}/*.stp +%endif + +%files relay +%{_sbindir}/dhcrelay +%attr(0644,root,root) %{_unitdir}/dhcrelay.service +%attr(0644,root,root) %{_mandir}/man8/dhcrelay.8.gz + +%files client +%doc README.dhclient.d +%doc client/dhclient.conf.example client/dhclient6.conf.example client/dhclient-enter-hooks +%attr(0750,root,root) %dir %{dhcpconfdir} +%dir %{dhcpconfdir}/dhclient.d +%dir %{_localstatedir}/lib/dhclient +%dir %{_prefix}/lib/NetworkManager +%dir %{_prefix}/lib/NetworkManager/dispatcher.d +%{_prefix}/lib/NetworkManager/dispatcher.d/11-dhclient +%{_sbindir}/dhclient +%{_sbindir}/dhclient-script +%attr(0755,root,root) %{_libdir}/pm-utils/sleep.d/56dhclient +%attr(0644,root,root) %{_mandir}/man5/dhclient.conf.5.gz +%attr(0644,root,root) %{_mandir}/man5/dhclient.leases.5.gz +%attr(0644,root,root) %{_mandir}/man8/dhclient.8.gz +%attr(0644,root,root) %{_mandir}/man8/dhclient-script.8.gz + +%files common +%{!?_licensedir:%global license %%doc} +%{license} LICENSE +%doc README RELNOTES doc/References.txt +%attr(0644,root,root) %{_mandir}/man5/dhcp-options.5.gz +%attr(0644,root,root) %{_mandir}/man5/dhcp-eval.5.gz + +%files libs-static +%{_libdir}/libdhcp*.a +%{_libdir}/libomapi.a + +%files devel +%doc doc/IANA-arp-parameters doc/api+protocol +%{_includedir}/dhcpctl +%{_includedir}/omapip +%attr(0644,root,root) %{_mandir}/man3/dhcpctl.3.gz +%attr(0644,root,root) %{_mandir}/man3/omapi.3.gz + +%if ! 0%{?_module_build} +%files devel-doc +%doc doc/html/ +%endif + +%changelog +* Mon Aug 09 2021 Mohan Boddu - 12:4.4.2-15.b1 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Thu Jul 8 2021 Pavel Zhukov - 12:4.4.2-14.b1 +- Fix for CVE-2021-25217 + +* Mon Jun 14 2021 Pavel Zhukov - 12:4.4.2-13.b1 +- Do not export getaddrinfo from irs libs (#1969858) + +* Fri Jun 11 2021 Pavel Zhukov - 12:4.4.2-11.b1 +- Drop compat package finally + +* Thu Apr 15 2021 Mohan Boddu - 12:4.4.2-10.b1 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Tue Jan 26 2021 Fedora Release Engineering - 12:4.4.2-9.b1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Wed Jul 29 2020 Pavel Zhukov - 12:4.4.2-8.b1 +- Fix IB patch (#1860689) + +* Mon Jul 27 2020 Fedora Release Engineering - 12:4.4.2-7.b1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Wed Apr 22 2020 Pavel Zhukov - 12:4.4.2-6.b1 +- Change upstream URL + +* Fri Feb 21 2020 Pavel Zhukov - 12:4.4.2-5.b1 +- Workarounnd for gcc10 + +* Tue Jan 28 2020 Fedora Release Engineering - 12:4.4.2-4.b1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Mon Jan 6 2020 Pavel Zhukov - 12:4.4.2-3.b1 +- Drop NetworkManager 12-dhcpd script. It's deprecated by wait-online (#1780861) + +* Mon Jan 6 2020 Pavel Zhukov - 12:4.4.2-1.b1 +- Dropped all (pre 4.0.0) changelog +- New version (4.4.2b1) + +* Wed Nov 27 2019 Pavel Zhukov - 12:4.4.1-20 +- Fix leak of file descriptors + +* Mon Nov 11 2019 Pavel Zhukov - 12:4.4.1-19 +- Reword -B option description + +* Thu Nov 7 2019 Pavel Zhukov - 12:4.4.1-18 +- Readd sd-notify patch + +* Thu Aug 22 2019 Lubomir Rintel - 12:4.4.1-17 +- Move the NetworkManager dispatcher script out of /etc + +* Thu Jul 25 2019 Pavel Zhukov - 12:4.4.1-16 +- Split timers patch to bind and dhcp parts + +* Wed Jul 24 2019 Fedora Release Engineering - 12:4.4.1-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Thu Jul 11 2019 Pavel Zhukov - 12:4.4.1-14 +- Detect time change and request lease renewal + +* Mon May 20 2019 Pavel Zhukov - 12:4.4.1-13 +- Unpack bind prior to patching +- Provide noarch libs + +* Sat May 04 2019 Björn Esser - 12:4.4.1-12 +- rebuilt (bind) + +* Tue Apr 2 2019 Pavel Zhukov - 12:4.4.1-11 +- Specify epoch for obsolete + +* Tue Apr 2 2019 Pavel Zhukov - 12:4.4.1-10 +- Cherry-pick 00b7f9a Specify architecture for provides - + +* Tue Apr 2 2019 Pavel Zhukov - 12:4.4.1-9 +- Move obsolete to common section + +* Wed Mar 27 2019 Pavel Zhukov - 12:4.4.1-8 +- Add sd_notify patch to support systemd notify (1687040) + +* Mon Mar 18 2019 Pavel Zhukov - 12:4.4.1-7 +- Provides specific version of libs + +* Mon Mar 18 2019 Pavel Zhukov - 12:4.4.1-6 +- Obsolete dhcp-libs + +* Wed Mar 13 2019 Pavel Zhukov - 12:4.4.1-5 +- Do not require static libs for non devel installations + +* Thu Feb 28 2019 Pavel Zhukov - 12:4.4.1-3 +- New version 4.4.1 + +* Mon Sep 24 2018 Pavel Zhukov - 12:4.3.6-29 +- Resolves: 1632246 - Do not fail if iface has no hwaddr + +* Thu Aug 30 2018 Pavel Zhukov - 12:4.3.6-28 +- Do not try to map leases file in memory if not in replay mode + +* Fri Jul 13 2018 Petr Menšík - 12:4.3.6-27 +- Update to bind 9.11.4 + +* Thu Jul 12 2018 Fedora Release Engineering - 12:4.3.6-26 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Mon Jun 18 2018 Pavel Zhukov - 12:4.3.6-25 +- Resolves: 1592239 - Handle dhcp4-change event properly + +* Mon May 21 2018 Pavel Zhukov - 12:4.3.6-24 +- Fix few more shellcheck warnings + +* Fri May 18 2018 Pavel Zhukov - 12:4.3.6-23 +- Get rid of eval in 11-dhclient +- Credits to legolegs user of linux.org.ru + +* Tue May 15 2018 Pavel Zhukov - 12:4.3.6-21 +- Fix for CVE-2018-1111 + +* Fri Apr 6 2018 Pavel Zhukov - 12:4.3.6-20 +- Discover hwaddr for all interfaces for xid uniqueness + +* Wed Mar 21 2018 Pavel Zhukov - 12:4.3.6-19 +- Don't use run-parts for hooks discovery (#1558612) + +* Fri Mar 09 2018 Pavel Zhukov - 12:4.3.6-18 +- Own ldap schema directory (#1553432) + +* Thu Mar 1 2018 Pavel Zhukov - 12:4.3.6-17 +- Fix CVE-2018-5732 CVE-2018-5733 (#1550246) + +* Thu Feb 22 2018 Petr Menšík - 12:4.3.6-16 +- Compile with recent bind includes, that does not include isc/util.h + +* Thu Feb 22 2018 Petr Menšík - 12:4.3.6-15 +- Do not rely on ignoring case sensitivity of VERSION variable + +* Thu Feb 22 2018 Petr Menšík - 12:4.3.6-14 +- Use bind-export-libs package instead of bind99 +- Use isc-config.sh to configure bind libs +- Change requirement to bind-export-devel + +* Thu Feb 22 2018 Pavel Zhukov - 12:4.3.6-13 +- Do not parse sysconfig/network-scripts if initscripts not installed (#1098172) + +* Wed Feb 07 2018 Fedora Release Engineering - 12:4.3.6-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Sat Feb 03 2018 Igor Gnatenko - 12:4.3.6-11 +- Switch to %%ldconfig_scriptlets + +* Wed Jan 10 2018 Pavel Zhukov - 12:4.3.6-10 +- Use released version + +* Wed Dec 20 2017 Pavel Zhukov - 12:4.3.5-9 +- Change duid_uuid patch to not use std99 feature + +* Fri Dec 8 2017 Pavel Zhukov - 12:4.3.6-8 +- Fix omapi SD leak (#1523547) + +* Thu Nov 9 2017 Pavel Zhukov - 12:4.3.6-7 +- Add patch for proper signal handling with shared context (#1457871) + +* Wed Sep 20 2017 Pavel Zhukov - 12:4.3.6-6 +- Do now override hostname variable in script + +* Sun Sep 10 2017 Peter Robinson 12:4.3.6-5 +- Rebuild for bind 9.9.11 + +* Tue Aug 1 2017 Pavel Zhukov - 12:4.3.6-4 +- Fix typos in dhclient-script + +* Thu Jul 27 2017 Pavel Zhukov - 12:4.3.6-3 +- Recreate /etc/resolv.conf if NetworkManager screwed it up (#1475279) + +* Wed Jul 26 2017 Fedora Release Engineering - 12:4.3.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + + +* Fri Jul 14 2017 Pavel Zhukov - 12:4.3.6-1 +- New version 4.3.6 + +* Fri Jul 07 2017 Igor Gnatenko - 12:4.3.5-10 +- Rebuild due to bug in RPM (RHBZ #1468476) + +* Mon Jul 03 2017 Petr Menšík - 12:4.3.5-9 +- Rebuild for bind 9.9.10 + +* Wed May 31 2017 Pavel Zhukov - 12:4.3.5-8 +- Drop chown from the post section + +* Tue May 23 2017 Pavel Zhukov - 12:4.3.5-7 +- Don't open ddns port until it's needed. Credits to Petr Menšík for the original idea + +* Wed Apr 19 2017 Dominika Hodovska - 12:4.3.5-5 +- don't build doxygen documentation during modular build + +* Tue Apr 04 2017 Pavel Zhukov - 12:4.3.5-4 +- Add EnvironmentFile parameter for backward compatibility + +* Fri Feb 10 2017 Fedora Release Engineering - 12:4.3.5-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Wed Nov 30 2016 Jiri Popelka - 12:4.3.5-2 +- get BUG_REPORT_URL from /etc/os-release (#1399351) + +* Wed Oct 05 2016 Jiri Popelka - 12:4.3.5-1 +- 4.3.5 + +* Mon Sep 12 2016 Jiri Popelka - 12:4.3.5-0.1b1 +- 4.3.5b1 + +* Wed Aug 03 2016 Jiri Popelka - 12:4.3.4-3 +- [dhclient] rename -R option to --request-options (#1357947) +- [dhclient] rename -timeout option to --timeout + +* Thu May 26 2016 Tomas Hozza - 12:4.3.4-2 +- Rebuild against bind99-9.9.9-P1 + +* Fri Apr 29 2016 Jiri Popelka - 12:4.3.4-1 +- 4.3.4 +- disable systemtap (I don't think anybody ever used it) + +* Wed Mar 23 2016 Zdenek Dohnal zdohnal@redhat.com - 12:4.3.3-13.P1 +- Mentioning the bash script is needed in README.dhclient.d + +* Wed Feb 03 2016 Fedora Release Engineering - 12:4.3.3-12.P1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Jan 13 2016 Jiri Popelka - 12:4.3.3-11.P1 +- 4.3.3-P1 - fix for CVE-2015-8605 (#1298077) + +* Wed Dec 16 2015 Tomas Hozza - 12:4.3.3-10 +- Rebuild against bind-9.9.8-P2 + +* Mon Dec 14 2015 Jiri Popelka - 12:4.3.3-9 +- implement DUID-UUID (RFC 6355) and make it default DUID type (#560361#60) + +* Tue Nov 24 2015 Jiri Popelka - 12:4.3.3-8 +- dispatcher.d/12-dhcpd: use reset-failed command + +* Mon Nov 23 2015 Jiri Popelka - 12:4.3.3-7 +- dhclient-script: hostname -> hostnamectl --transient + +* Tue Nov 03 2015 Jiri Popelka - 12:4.3.3-6 +- dhclient-script: source ifcfg-* because of PEERDNS (#1277253) + +* Tue Oct 13 2015 Jiri Popelka - 12:4.3.3-5 +- dhclient-script: fix for gateway not in the end of rfc3442 routes list (#1251644) + +* Tue Oct 13 2015 Jiri Popelka - 12:4.3.3-4 +- dhclient-script: make_resolv_conf(): keep old nameservers + if server sends domain-name/search, but no nameservers (#1269595) + +* Tue Sep 22 2015 Jiri Popelka - 12:4.3.3-3 +- dhclient: make sure link-local address is ready in stateless mode (#1263466) + +* Mon Sep 07 2015 Jiri Popelka - 12:4.3.3-2 +- VLAN ID is only bottom 12-bits of TCI (#1259552) + +* Fri Sep 04 2015 Jiri Popelka - 12:4.3.3-1 +- 4.3.3 + +* Tue Aug 11 2015 Jiri Popelka - 12:4.3.3-0.2b1 +- dhclient-script: respect DEFROUTE/GATEWAYDEV if Classless Static Routes are offered (#1251644) + +* Mon Aug 10 2015 Jiri Popelka - 12:4.3.3-0.1b1 +- 4.3.3b1 +- enable krb5/gssapi authentication for OpenLDAP +- enable support for binary insertion of leases + +* Wed Jul 15 2015 Jiri Popelka - 12:4.3.2-12 +- fix ipcalc requires + +* Tue Jul 14 2015 Jiri Popelka - 12:4.3.2-11 +- remove dependency on initscripts (#1098172) +- make path to resolv.conf configurable (#1086425) + +* Thu Jul 09 2015 Jiri Popelka - 12:4.3.2-10 +- spec cleanup + +* Thu Jul 02 2015 Jiri Popelka - 12:4.3.2-9 +- test upstream fix for #866714 (paranoia.patch) + +* Wed Jun 24 2015 Jiri Popelka - 12:4.3.2-8 +- add more randomness into xid generation (#1195693) + +* Wed Jun 17 2015 Fedora Release Engineering - 12:4.3.2-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Tue May 26 2015 Jiri Popelka - 12:4.3.2-6 +- dhclient-script: run also scripts in dhclient-[enter/exit]-hooks.d dir + +* Tue Apr 21 2015 Jiri Popelka - 12:4.3.2-5 +- dhclient-script: add a minute to address lifetimes (#1188423) + +* Mon Apr 13 2015 Jiri Popelka - 12:4.3.2-4 +- dhclient-script: amend previous change (#1210984) + +* Wed Mar 25 2015 Jiri Popelka - 12:4.3.2-3 +- dhclient-script: fix shellcheck.net suggestions + +* Fri Mar 13 2015 Tomas Hozza - 12:4.3.2-2 +- rebuild against bind99 9.9.7 package + +* Thu Mar 05 2015 Jiri Popelka - 12:4.3.2-1 +- 4.3.2 + +* Wed Feb 25 2015 Jiri Popelka - 12:4.3.2-0.6b1 +- correctly set IB's hw->hlen (#1185075) + +* Wed Feb 25 2015 Tomas Hozza - 12:4.3.2-0.5b1 +- Rebuild against bind-9.10.2rc2 + +* Tue Feb 17 2015 Jiri Popelka - 12:4.3.2-0.4b1 +- dhclient-script: use 'ip addr replace' for both BOUND & RENEW + +* Tue Feb 17 2015 Jiri Popelka - 12:4.3.2-0.3b1 +- doc/dhclient/dhclient-enter-hooks for dhclient-script debugging + +* Fri Feb 13 2015 Jiri Popelka - 12:4.3.2-0.2b1 +- dhclient-script: s/addr add/addr replace/ + +* Sun Feb 08 2015 Jiri Popelka - 12:4.3.2-0.1b1 +- 4.3.2b1 + +* Tue Feb 03 2015 Jiri Popelka - 12:4.3.1-21 +- send unicast request/release via correct interface (#800561, #1177351) + +* Mon Feb 02 2015 Tomas Hozza - 12:4.3.1-20 +- rebuild against bind-9.10.2rc1 + +* Wed Jan 14 2015 Tomas Hozza - 12:4.3.1-19 +- rebuild against bind 9.10.1-P1 + +* Thu Dec 18 2014 Jiri Popelka - 12:4.3.1-18 +- dhclient: write DUID_LLT even in stateless mode (#1156356) + +* Wed Dec 17 2014 Jiri Popelka - 12:4.3.1-17 +- option 97 - pxe-client-id (#1058674) + +* Wed Nov 19 2014 Jiri Popelka - 12:4.3.1-16 +- amend post scriptlets for #1120656 + +* Mon Nov 10 2014 Jiri Popelka - 12:4.3.1-15 +- dhclient-script: restorecon calls shouldn't be needed + as we have SELinux transition rules (#1161500) + +* Tue Nov 04 2014 Jiri Popelka - 12:4.3.1-14 +- GSSAPI support for ldap authentication (#1150542) + +* Fri Oct 31 2014 Jiri Popelka - 12:4.3.1-13 +- redefine DHCLIENT_DEFAULT_PREFIX_LEN 64 -> 128 + +* Fri Oct 10 2014 Jiri Popelka - 12:4.3.1-12 +- Relay-forward Message's Hop Limit should be 32 (#1147240) + +* Wed Oct 08 2014 Jiri Popelka - 12:4.3.1-11 +- dhcpd generates spurious responses when seeing requests + from vlans on plain interface (#1150587) + +* Fri Oct 03 2014 Tomas Hozza - 12:4.3.1-10 +- rebuild against bind-9.9.6 + +* Thu Sep 04 2014 Jiri Popelka - 12:4.3.1-9 +- [dhclient -6] infinite preferred/valid lifetime represented as -1 (#1133839) + +* Mon Sep 01 2014 Jiri Popelka - 12:4.3.1-8 +- better obsoletes for server & client + +* Sat Aug 30 2014 Kalev Lember - 12:4.3.1-7 +- Fix dhclient obsoletes version + +* Tue Aug 26 2014 Jiri Popelka - 12:4.3.1-6 +- dhclient-script: another improvement of add_ipv6_addr_with_DAD() + +* Mon Aug 25 2014 Jiri Popelka - 12:4.3.1-5 +- spec: use -D with 'install' +- dhclient-script: IPv6 address which fails DAD is auto-removed when it was + added with valid_lft/preferred_lft other then 'forever' (#1133465) + +* Sat Aug 16 2014 Fedora Release Engineering - 12:4.3.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Thu Aug 14 2014 Jiri Popelka - 12:4.3.1-3 +- dhclient-script: one more fix for #1129500 + +* Thu Aug 14 2014 Jiri Popelka - 12:4.3.1-2 +- dhclient-script: PREINIT6: make sure link-local address is available (#1129500) + +* Tue Aug 12 2014 Jiri Popelka - 12:4.3.1-1 +- 4.3.1 + +* Tue Aug 05 2014 Jiri Popelka - 12:4.3.1-0.4.b1 +- dhclient-script: it's OK if the arping reply comes from our system (#1116004) + +* Tue Jul 22 2014 Jiri Popelka - 12:4.3.1-0.3.b1 +- Use network-online.target instead of network.target (#1120656) + +* Fri Jul 11 2014 Tom Callaway 12:4.3.1-0.2.b1 +- fix license handling + +* Thu Jul 10 2014 Jiri Popelka - 12:4.3.1-0.1.b1 +- 4.3.1b1 + +* Thu Jun 12 2014 Filipe Brandenburger - 12:4.3.0-15 +- dhclient-script: fix issue with classless static routes that breaks Fedora 20 on GCE cloud (#1102830) + +* Sat Jun 07 2014 Fedora Release Engineering - 12:4.3.0-14 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Fri May 30 2014 Jiri Popelka - 12:4.3.0-13 +- systemtap: fixed dtrace input file (#1102797) + +* Thu May 29 2014 Jiri Popelka - 12:4.3.0-12 +- dhcp-sd_notify.patch BuildRequires: pkgconfig(libsystemd) + +* Wed May 28 2014 Jiri Popelka - 12:4.3.0-11 +- dhclient-script: fix stateless DHCPv6 mode (#1101149) + +* Wed May 07 2014 Jiri Popelka - 12:4.3.0-10 +- use StandardError=null instead of log_perror.patch + +* Tue Mar 18 2014 Jiri Popelka - 12:4.3.0-9 +- support for sending startup notifications to systemd (#1077666) + +* Fri Mar 07 2014 Jiri Popelka - 12:4.3.0-8 +- rename doc subpackage do devel-doc + +* Mon Mar 03 2014 Jaromír Končický - 12:4.3.0-7 +- added 'doc' package containing doxygen-generated documentation + +* Wed Feb 19 2014 Jiri Popelka - 12:4.3.0-6 +- dhclient: rename our -I option to -C as upstream now uses -I + +* Wed Feb 19 2014 Jiri Popelka - 12:4.3.0-5 +- dhclient-script: don't flush all addresses, just the used one + +* Tue Feb 18 2014 Jiri Popelka - 12:4.3.0-4 +- IPoIB: add GUID/DUID to dhcpd logs (#1064416) + +* Mon Feb 17 2014 Jiri Popelka - 12:4.3.0-3 +- don't try to run tests because there's no atf package since F21 + +* Mon Feb 17 2014 Jiri Popelka - 12:4.3.0-2 +- turn on using of DUID with DHCPv4 clients (#560361,c#40) +- remove default /etc/dhcp/dhclient.conf + +* Tue Feb 04 2014 Jiri Popelka - 12:4.3.0-1 +- 4.3.0 + +* Wed Jan 29 2014 Jiri Popelka - 12:4.3.0-0.7.rc1 +- 4.3.0rc1 + +* Tue Jan 28 2014 Jiri Popelka - 12:4.3.0-0.6.b1 +- don't apply retransmission.patch for now (RHBZ#1026565) + +* Sun Jan 26 2014 Kevin Fenzi 12:4.3.0-0.5.b1 +- Rebuild for new bind + +* Tue Jan 21 2014 Jiri Popelka - 12:4.3.0-0.4.b1 +- 4.3.0b1 +- ship dhcp-lease-list.pl +- dhclient-script: don't ping router (#1055181) + +* Mon Jan 13 2014 Jiri Popelka - 12:4.3.0-0.3.a1 +- update address lifetimes on RENEW/RENEW6 (#1032809) + +* Tue Jan 07 2014 Jiri Popelka - 12:4.3.0-0.2.a1 +- make it actually build + +* Thu Dec 19 2013 Jiri Popelka - 12:4.3.0-0.1.a1 +- 4.3.0a1: requires bind-9.9.5 + +* Thu Nov 21 2013 Jiri Popelka - 12:4.2.5-28 +- dhclient-script: set address lifetimes (#1032809) + +* Thu Nov 14 2013 Jiri Popelka - 12:4.2.5-27 +- dhclient-script(RENEW6|REBIND6): delete old ip6_address if it changed (#1015729) + +* Thu Oct 31 2013 Jiri Popelka - 12:4.2.5-26 +- Provide default /etc/dhcp/dhclient.conf +- Client always sends dhcp-client-identifier (#560361) + +* Thu Oct 24 2013 Jiri Popelka - 12:4.2.5-25 +- use upstream patch for #1001742 ([ISC-Bugs #34784]) + +* Mon Oct 07 2013 Jiri Popelka - 12:4.2.5-24 +- dhcpd rejects the udp packet with checksum=0xffff (#1015997) + +* Fri Sep 27 2013 Jiri Popelka - 12:4.2.5-23 +- 'No subnet declaration for ' should be info, not error +- decrease the sleep in 12-dhcpd due to timeout (#1003695#8) + +* Wed Sep 18 2013 Jiri Popelka - 12:4.2.5-22 +- fix segfault introduced with previous commit + +* Tue Sep 17 2013 Jiri Popelka - 12:4.2.5-21 +- 12-dhcpd: wait a few seconds before restarting services (#1003695) +- another solution for #1001742 (#1005814#c10) + +* Thu Sep 12 2013 Jiri Popelka - 12:4.2.5-20 +- bind DHCPv6 client to link-local address instead of 0 address (#1001742) + +* Mon Aug 26 2013 Jiri Popelka - 12:4.2.5-19 +- don't crash on aliased infiniband interface (#996518) + +* Sun Aug 04 2013 Jiri Popelka - 12:4.2.5-18 +- BuildRequires: systemd due to %%{_unitdir} + +* Mon Jul 29 2013 Jiri Popelka - 12:4.2.5-17 +- 12-dhcpd previously exited with error status 1 (#989207) + +* Mon Jul 15 2013 Tomas Hozza - 12:4.2.5-16 +- rebuild against new bind + +* Tue Jul 02 2013 Jiri Popelka - 12:4.2.5-15 +- fix several memory leaks in omapi (#978420) +- remove send_release.patch (#979510) + +* Tue Jun 18 2013 Jiri Popelka - 12:4.2.5-14 +- rebuilt against bind once more + +* Fri Jun 14 2013 Jiri Popelka - 12:4.2.5-13 +- return /etc/sysconfig/dhcpd back, but do NOT use it (#909733) + +* Tue May 14 2013 Adam Williamson - 12:4.2.5-12 +- rebuild against new bind + +* Tue Apr 30 2013 Jiri Popelka - 12:4.2.5-11 +- add missing conversion specifier in log_fatal() call (#957371) + +* Tue Apr 16 2013 Adam Tkac - 12:4.2.5-10 +- rebuild against new bind + +* Wed Apr 03 2013 Tomas Hozza - 12:4.2.5-9 +- Expose next-server DHCPv4 option to dhclient script + +* Tue Mar 26 2013 Jiri Popelka - 12:4.2.5-8 +- describe -user/-group/-chroot in dhcpd.8 + +* Fri Feb 22 2013 Jiri Popelka - 12:4.2.5-7 +- remove triggerun condition (#895475) + +* Wed Feb 13 2013 Fedora Release Engineering - 12:4.2.5-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Thu Jan 24 2013 Jiri Popelka - 12:4.2.5-5 +- remove missing-ipv6-not-fatal.patch because the concerning code is later + removed with getifaddrs.patch + +* Wed Jan 23 2013 Jiri Popelka - 12:4.2.5-4 +- Make sure range6 is correct for subnet6 where it's declared (#902966) + +* Fri Jan 18 2013 Jiri Popelka - 12:4.2.5-3 +- simplify the previously added triggerun scriptlet + +* Thu Jan 17 2013 Jiri Popelka - 12:4.2.5-2 +- during update convert DHC*ARGS from /etc/sysconfig/dhc* + to /etc/systemd/system/dhc*.service (#895475) +- 12-dhcpd NM dispatcher script now restarts also dhcpd6 service + +* Thu Jan 10 2013 Jiri Popelka - 12:4.2.5-1 +- 4.2.5 + +* Wed Jan 02 2013 Jiri Popelka - 12:4.2.5-0.3.rc1 +- run %%check in Fedora only, there's no atf package in RHEL + +* Thu Dec 20 2012 Jiri Popelka - 12:4.2.5-0.2.rc1 +- don't package ancient contrib/* files + +* Thu Dec 20 2012 Jiri Popelka - 12:4.2.5-0.1.rc1 +- 4.2.5rc1 + - added %%check - upstream unit tests (Automated Test Framework - ATF) + +* Fri Nov 30 2012 Jiri Popelka - 12:4.2.4-23.P2 +- fix two resource leaks in lpf-ib.patch + +* Mon Nov 26 2012 Jiri Popelka - 12:4.2.4-22.P2 +- add After=time-sync.target to dhcpd[6].service (#878293) +- remove groff from BuildRequires (no idea why it's been there) + +* Fri Nov 16 2012 Jiri Popelka - 12:4.2.4-21.P2 +- multiple key statements in zone definition causes inappropriate error (#873794) + +* Fri Oct 26 2012 Jiri Popelka - 12:4.2.4-20.P2 +- fix path to dhcpd6.leases in dhcpd6.conf.sample (#870458) + +* Wed Oct 17 2012 Jiri Popelka - 12:4.2.4-19.P2 +- dhcpd needs to chown leases file created before de-rooting itself (#866714) + +* Thu Oct 11 2012 Adam Tkac - 12:4.2.4-18.P2 +- rebuild against new bind-libs-lite + +* Tue Oct 09 2012 Jiri Popelka - 12:4.2.4-17.P2 +- do-forward-updates statement wasn't recognized (#863646) + +* Wed Sep 26 2012 Jiri Popelka - 12:4.2.4-16.P2 +- dhclient-usage.patch+part of manpages.patch merged with dhclient-options.patch + +* Thu Sep 13 2012 Tomas Hozza - 12:4.2.4-15.P2 +- 4.2.4-P2: fix for CVE-2012-3955 (#856770) + +* Fri Aug 24 2012 Tomas Hozza - 12:4.2.4-14.P1 +- SystemD unit files don't use Environment files any more (#850558) +- NetworkManager dispatcher script doesn't use DHCPDARGS any more + +* Wed Aug 22 2012 Tomas Hozza - 12:4.2.4-13.P1 +- fixed SPEC file so it comply with new systemd-rpm macros guidelines (#850089) + +* Mon Aug 20 2012 Tomas Hozza - 12:4.2.4-12.P1 +- dhclient-script: fixed CONFIG variable value passed to need_config (#848858) +- dhclient-script: calling dhclient-up-hooks after setting up route, gateways + & interface alias (#848869) + +* Fri Aug 17 2012 Jiri Popelka - 12:4.2.4-11.P1 +- don't build libdst, it hasn't been used since 4.2.0 (#849166) + +* Fri Jul 27 2012 Jiri Popelka - 12:4.2.4-10.P1 +- isc_time_nowplusinterval() is not safe with 64-bit time_t (#662254, #789601) + +* Fri Jul 27 2012 Fedora Release Engineering - 12:4.2.4-9.P1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Wed Jul 25 2012 Tomas Hozza - 12:4.2.4-8.P1 +- Dhclient does not correctly parse zero-length options in + dhclient6.leases (#633318) + +* Wed Jul 25 2012 Tomas Hozza - 12:4.2.4-7.P1 +- 4.2.4-P1: fix for CVE-2012-3570 CVE-2012-3571 and CVE-2012-3954 (#842892) + +* Mon Jul 23 2012 Jiri Popelka - 12:4.2.4-6 +- ib.patch: added fall-back method (using ioctl(SIOCGIFHWADDR)) when getting + of HW address with getifaddrs() fails (#626514-c#63, #840601). + +* Mon Jul 23 2012 Tomas Hozza - 12:4.2.4-5 +- Dhcpd does not correctly follow DhcpFailOverPeerDN (#838400) + +* Wed Jul 18 2012 Jiri Popelka - 12:4.2.4-4 +- allow dhcpd to listen on alias interfaces (#840601) + +* Mon Jul 09 2012 Tomas Hozza - 12:4.2.4-3 +- changed list of %%verify on the leases files (#837474) + +* Mon Jun 18 2012 Jiri Popelka - 12:4.2.4-2 +- define $SAVEDIR in dhclient-script (#833054) + +* Wed Jun 06 2012 Jiri Popelka - 12:4.2.4-1 +- 4.2.4 + +* Tue Jun 05 2012 Jiri Popelka - 12:4.2.4-0.8.rc2 +- return prematurely removed 12-dhcpd (NM dispatcher script) (#828522) + +* Fri May 25 2012 Jiri Popelka - 12:4.2.4-0.7.rc2 +- getifaddrs.patch: use HAVE_SA_LEN macro + +* Wed May 23 2012 Jiri Popelka - 12:4.2.4-0.6.rc2 +- 4.2.4rc2 + +* Mon May 07 2012 Jiri Popelka - 12:4.2.4-0.5.rc1 +- dhcpd.service: explicitly add -cf to indicate what conf file we use (#819325) +- no need to copy /etc/*.conf to /etc/dhcp/*.conf in %%prep anymore + +* Tue May 01 2012 Jiri Popelka - 12:4.2.4-0.4.rc1 +- 4.2.4rc1 + +* Thu Apr 26 2012 Jiri Popelka - 12:4.2.4-0.3.b1 +- remove inherit-leases.patch - it's probably not needed anymore (#815355) + +* Wed Apr 18 2012 Jiri Popelka - 12:4.2.4-0.2.b1 +- update paths.patch and source URL + +* Mon Apr 16 2012 Jiri Popelka - 12:4.2.4-0.1.b1 +- 4.2.4b1: noprefixavail.patch merged upstream + +* Fri Mar 30 2012 Jiri Popelka - 12:4.2.3-25.P2 +- move dhclient & dhclient-script from /sbin to /usr/sbin + +* Fri Mar 23 2012 Jiri Popelka - 12:4.2.3-24.P2 +- one more fix (#806342) + +* Fri Mar 23 2012 Jiri Popelka - 12:4.2.3-23.P2 +- improve #449946 fix (#806342) + +* Wed Mar 21 2012 Jiri Popelka - 12:4.2.3-22.P2 +- RFC5970 - DHCPv6 Options for Network Boot (#798735) + +* Wed Mar 21 2012 Jiri Popelka - 12:4.2.3-21.P2 +- don't use fallback_interface when releasing lease (#800561) + +* Wed Mar 21 2012 Jiri Popelka - 12:4.2.3-20.P2 +- use getifaddrs() to scan for interfaces on Linux (#449946) + +* Wed Feb 22 2012 Jiri Popelka - 12:4.2.3-19.P2 +- don't send log messages to the standard error descriptor by default (#790387) + +* Mon Feb 13 2012 Jiri Popelka - 12:4.2.3-18.P2 +- -timeout option (command line) with value 3 or less was driving dhclient mad (#789719) + +* Tue Feb 07 2012 Jiri Popelka - 12:4.2.3-17.P2 +- dhclient-script: install link-local static routes with correct scope (#787318) + +* Wed Feb 1 2012 Adam Williamson - 12:4.2.3-16.P2 +- rebuild for new bind-libs-lite + +* Tue Jan 31 2012 Jiri Popelka - 12:4.2.3-15.P2 +- revert previous change (#782499) +- remove the rest of the sysvinit scriptlets + +* Tue Jan 17 2012 Jiri Popelka - 12:4.2.3-14.P2 +- use PrivateTmp=true in service files (#782499) + +* Fri Jan 13 2012 Jiri Popelka - 12:4.2.3-13.P2 +- 4.2.3-P2: fix for CVE-2011-4868 (#781246) +- clean up old Provides and Obsoletes + +* Fri Jan 13 2012 Fedora Release Engineering - 12:4.2.3-12.P1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Dec 21 2011 Jiri Popelka - 12:4.2.3-11.P1 +- revert change made in 4.2.3-3 because of failing failover inicialization (#765967) + the procedure is now: + init lease file, init failover, init PID file, change effective user/group ID +- don't need to fix lease files ownership before starting service +- dhclient-script: allow static route with a 0.0.0.0 next-hop address (#769463) + +* Tue Dec 20 2011 Jiri Popelka - 12:4.2.3-10.P1 +- hopefully we don't need 12-dhcpd anymore as 'After=network.target' + in dhcpd[6].service should take care of the original problem (#565921) + +* Mon Dec 19 2011 Jiri Popelka - 12:4.2.3-9.P1 +- don't ship legacy SysV initscripts +- dhcpd6: move '-cf /etc/dhcp/dhcpd6.conf' from sysconfig/dhcpd6 to dhcpd6.service +- run 'chown -R dhcpd:dhcpd /var/lib/dhcpd/' before starting dhcpd/dhcpd6 service + for the case where leases file is owned by root:root as a + consequence of running dhcpd without '-user dhcpd -group dhcpd' (#744292) + +* Fri Dec 09 2011 Jiri Popelka - 12:4.2.3-8.P1 +- 4.2.3-P1: fix for CVE-2011-4539 (#765681) + +* Thu Nov 24 2011 Jiri Popelka - 12:4.2.3-7 +- Send DHCPDECLINE and exit(2) when duplicate address was detected and + dhclient had been started with '-1' (#756759). +- Don't build with -D_GNU_SOURCE, configure.ac uses AC_USE_SYSTEM_EXTENSIONS + +* Mon Nov 14 2011 Adam Tkac - 12:4.2.3-6 +- rebuild against new bind + +* Fri Nov 11 2011 Jiri Popelka - 12:4.2.3-5 +- dhclient-script: arping address in BOUND|RENEW|REBIND|REBOOT (#752116) + +* Wed Oct 26 2011 Fedora Release Engineering - 12:4.2.3-4 +- Rebuilt for glibc bug#747377 + +* Wed Oct 26 2011 Jiri Popelka - 12:4.2.3-3 +- Write lease file AFTER changing of the effective user/group ID. +- Move omshell from dhcp-common to main package (where it originally was). + +* Thu Oct 20 2011 Jiri Popelka - 12:4.2.3-2 +- Write PID file BEFORE changing of the effective user/group ID. +- Really define _hardened_build this time + +* Thu Oct 20 2011 Jiri Popelka - 12:4.2.3-1 +- 4.2.3 + +* Tue Oct 18 2011 Jiri Popelka - 12:4.2.3-0.1.rc1 +- 4.2.3rc1 + +* Sun Oct 09 2011 Jiri Popelka - 12:4.2.2-12 +- change ownership of /var/lib/dhcpd/ to dhcpd:dhcpd (#744292) +- no need to drop capabilies in dhcpd since it's been running as regular user + +* Fri Sep 30 2011 Jiri Popelka - 12:4.2.2-11 +- 56dhclient: ifcfg file was not sourced (#742482) + +* Thu Sep 29 2011 Jiri Popelka - 12:4.2.2-10 +- dhclient-script: address alias handling fixes from Scott Shambarger (#741786) + +* Thu Sep 22 2011 Jiri Popelka - 12:4.2.2-9 +- dhclient-script: do not backup&restore /etc/resolv.conf and /etc/localtime. + +* Wed Sep 21 2011 Jiri Popelka - 12:4.2.2-8 +- SystemTap support: spec file change, some dummy probes, tapset, simple script + +* Mon Sep 19 2011 Jiri Popelka - 12:4.2.2-7 +- Support for IPoIB (IP over InfiniBand) interfaces (#660681) +- Hopefully last tweak of adding of user and group (#699713) + +* Fri Sep 09 2011 Jiri Popelka - 12:4.2.2-6 +- PIE-RELRO.patch is not needed anymore, defining _hardened_build does the same +- One more tweak of adding of user and group (#699713) + +* Fri Sep 09 2011 Adam Tkac - 12:4.2.2-5 +- rebuild against new bind + +* Fri Aug 26 2011 Jiri Popelka - 12:4.2.2-4 +- Fix adding of user and group (#699713) + +* Fri Aug 19 2011 Jiri Popelka - 12:4.2.2-3 +- Tighten explicit libs sub-package requirement so that it includes + the correct architecture as well. + +* Fri Aug 12 2011 Jiri Popelka - 12:4.2.2-2 +- #699713: + - Use '--enable-paranoia --enable-early-chroot' configure flags + - Create/delete dhcpd user in %%post/%%postun + - Run dhcpd/dhcpd6 services with '-user dhcpd -group dhcpd' + +* Thu Aug 11 2011 Jiri Popelka - 12:4.2.2-1 +- 4.2.2: fix for CVE-2011-2748, CVE-2011-2749 (#729850) + +* Wed Aug 10 2011 Jiri Popelka - 12:4.2.2-0.4.rc1 +- Do not ship default /etc/dhcp/dhclient.conf (#560361,c#9) + +* Mon Jul 25 2011 Jiri Popelka - 12:4.2.2-0.3.rc1 +- Improve capabilities patch to be able to run with PARANOIA & EARLY_CHROOT (#699713) + +* Mon Jul 18 2011 Jiri Popelka - 12:4.2.2-0.2.rc1 +- 4.2.2rc1 + +* Fri Jul 01 2011 Jiri Popelka - 12:4.2.2-0.1.b1 +- 4.2.2b1: upstream merged initialization-delay.patch +- Drop all capabilities in dhcpd/dhcrelay (#699713) + +* Fri Jun 17 2011 Jiri Popelka - 12:4.2.1-12.P1 +- Removed upstream-merged IFNAMSIZ.patch +- Polished patches according to results from static analysis of code. + +* Thu Jun 16 2011 Jiri Popelka - 12:4.2.1-11.P1 +- Add triggerpostun scriptlet tied to dhcp-sysvinit +- Make it possible to build without downstream patches (Kamil Dudka) + +* Tue May 17 2011 Jiri Popelka - 12:4.2.1-10.P1 +- Fix typo in triggerun scriptlet (#705417) + +* Mon May 16 2011 Jiri Popelka - 12:4.2.1-9.P1 +- Packages dhcp/dhclient/dhcp-common explicitly require the libs sub-package + with the same version and release (bug #705037). +- Fix triggerun scriptlet + +* Mon May 09 2011 Jiri Popelka - 12:4.2.1-8.P1 +- Fix 11-dhclient to export variables (#702735) + +* Fri Apr 29 2011 Jiri Popelka - 12:4.2.1-7.P1 +- Comply with guidelines for systemd services + +* Wed Apr 27 2011 Jiri Popelka - 12:4.2.1-6.P1 +- Fix NetworkManager dispatcher script for dhcpd to support arbitrary interface names + +* Wed Apr 06 2011 Jiri Popelka - 12:4.2.1-5.P1 +- Better fix for CVE-2011-0997: making domain-name check more lenient (#694005) + +* Wed Apr 06 2011 Jiri Popelka - 12:4.2.1-4.P1 +- 4.2.1-P1: fix for CVE-2011-0997 (#694005) + +* Fri Mar 25 2011 Jiri Popelka - 12:4.2.1-3 +- Polished patches according to results from static analysis of code. + +* Mon Mar 07 2011 Rex Dieter - 12:4.2.1-2 +- rebuild (bind) + +* Wed Mar 02 2011 Jiri Popelka - 12:4.2.1-1 +- 4.2.1 + +* Wed Feb 23 2011 Jiri Popelka - 12:4.2.1-0.6.rc1 +- 4.2.1rc1 +- Fixed typo in dhclient.leases(5) (#676284) + +* Mon Feb 21 2011 Adam Tkac - 12:4.2.1-0.5.b1 +- rebuild against new bind-libs-lite + +* Tue Feb 08 2011 Fedora Release Engineering - 12:4.2.1-0.4.b1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Jan 31 2011 Jiri Popelka - 12:4.2.1-0.3.b1 +- Prevent anything under _docdir from being scanned. (#674058) + +* Fri Jan 28 2011 Jiri Popelka - 12:4.2.1-0.2.b1 +- dhclient-script improvements, thanks to Ville Skyttä (#672279) + +* Thu Jan 27 2011 Jiri Popelka - 12:4.2.1-0.1.b1 +- 4.2.1b1: fix for CVE-2011-0413 (#672996) +- No longer need invalid-dhclient-conf, parse_date and release6-elapsed patches + +* Thu Jan 13 2011 Jiri Popelka - 12:4.2.0-26.P2 +- Fix loading of configuration when LDAP is used (#668276) + +* Mon Jan 03 2011 Jiri Popelka - 12:4.2.0-25.P2 +- Fix OMAPI (#666441) + +* Tue Dec 21 2010 Jiri Popelka - 12:4.2.0-24.P2 +- Provide default /etc/dhcp/dhclient.conf +- Client always sends dhcp-client-identifier (#560361) + +* Wed Dec 15 2010 Jiri Popelka - 12:4.2.0-23.P2 +- Add dhcp-common subpackage (#634673) + +* Mon Dec 13 2010 Jiri Popelka - 12:4.2.0-22.P2 +- 4.2.0-P2: fix for CVE-2010-3616 (#662326) +- Use upstream fix for #628258 +- Provide versioned symbols for rpmlint + +* Tue Dec 07 2010 Jiri Popelka - 12:4.2.0-21.P1 +- Porting dhcpd/dhcpd6/dhcrelay services from SysV to Systemd + +* Tue Nov 23 2010 Jiri Popelka - 12:4.2.0-20.P1 +- Remove explicit Obsoletes (#656310) + +* Fri Nov 19 2010 Dan Horák - 12:4.2.0-19.P1 +- fix build on sparc and s390 + +* Tue Nov 09 2010 Jiri Popelka - 12:4.2.0-18.P1 +- Applied Patrik Lahti's patch for DHCPv6 over PPP support (#626514) + +* Fri Nov 05 2010 Jiri Popelka - 12:4.2.0-17.P1 +- fix broken dependencies + +* Thu Nov 04 2010 Jiri Popelka - 12:4.2.0-16.P1 +- 4.2.0-P1: fix for CVE-2010-3611 (#649880) +- dhclient-script: when updating 'search' statement in resolv.conf, + add domain part of hostname if it's not already there (#637763) + +* Wed Oct 20 2010 Adam Tkac - 12:4.2.0-15 +- build dhcp's libraries as shared libs instead of static libs + +* Wed Oct 20 2010 Adam Tkac - 12:4.2.0-14 +- fire away bundled BIND source + +* Wed Oct 20 2010 Adam Tkac - 12:4.2.0-13 +- improve PIE patch (build libraries with -fpic, not with -fpie) + +* Wed Oct 13 2010 Jiri Popelka - 12:4.2.0-12 +- Server was ignoring client's + Solicit (where client included address/prefix as a preference) (#634842) + +* Thu Oct 07 2010 Jiri Popelka - 12:4.2.0-11 +- Use ping instead of arping in dhclient-script to handle + not-on-local-net gateway in ARP-less device (#524298) + +* Thu Oct 07 2010 Jiri Popelka - 12:4.2.0-10 +- Check whether there is any unexpired address in previous lease + prior to confirming (INIT-REBOOT) the lease (#585418) + +* Mon Oct 04 2010 Jiri Popelka - 12:4.2.0-9 +- RFC 3442 - ignore Router option only if + Classless Static Routes option contains default router + +* Thu Sep 30 2010 Jiri Popelka - 12:4.2.0-8 +- Explicitly clear the ARP cache and flush all addresses & routes + instead of bringing the interface down (#574568) + +* Tue Sep 07 2010 Jiri Popelka - 12:4.2.0-7 +- Hardening dhcpd/dhcrelay/dhclient by making them PIE & RELRO + +* Thu Sep 02 2010 Jiri Popelka - 12:4.2.0-6 +- Another fix for handling time values on 64-bit platforms (#628258) + +* Wed Sep 01 2010 Jiri Popelka - 12:4.2.0-5 +- Fix parsing of lease file dates & times on 64-bit platforms (#628258) + +* Tue Aug 31 2010 Jiri Popelka - 12:4.2.0-4 +- RFC 3442 - Classless Static Route Option for DHCPv4 (#516325) + +* Fri Aug 20 2010 Jiri Popelka - 12:4.2.0-3 +- Add DHCRELAYARGS variable to /etc/sysconfig/dhcrelay + +* Fri Jul 30 2010 Jiri Popelka - 12:4.2.0-2 +- Add 12-dhcpd NM dispatcher script (#565921) +- Rename 10-dhclient to 11-dhclient (10-sendmail already exists) + +* Wed Jul 21 2010 Jiri Popelka - 12:4.2.0-1 +- 4.2.0: includes ldap-for-dhcp + +* Mon Jul 12 2010 Jiri Popelka - 12:4.1.1-26.P1 +- Add LICENSE file to dhclient subpackage. + +* Thu Jul 01 2010 Jiri Popelka - 12:4.1.1-25.P1 +- Adhere to Static Library Packaging Guidelines (#609605) + +* Tue Jun 29 2010 Jiri Popelka - 12:4.1.1-24.P1 +- Fix parsing of date (#514828) + +* Thu Jun 03 2010 Jiri Popelka - 12:4.1.1-23.P1 +- 4.1.1-P1: pair of bug fixes including one for CVE-2010-2156 (#601405) +- Compile with -fno-strict-aliasing + +* Mon May 03 2010 Jiri Popelka - 12:4.1.1-22 +- Fix the initialization-delay.patch (#587070) + +* Thu Apr 29 2010 Jiri Popelka - 12:4.1.1-21 +- Cut down the 0-4 second delay before sending first DHCPDISCOVER (#587070) + +* Wed Apr 28 2010 Jiri Popelka - 12:4.1.1-20 +- Move /etc/NetworkManager/dispatcher.d/10-dhclient script + from dhcp to dhclient subpackage (#586999) + +* Wed Apr 28 2010 Jiri Popelka - 12:4.1.1-19 +- Add domain-search to the list of default requested DHCP options (#586906) + +* Wed Apr 21 2010 Jiri Popelka - 12:4.1.1-18 +- If the Reply was received in response to Renew or Rebind message, + client adds any new addresses in the IA option to the IA (#578097) + +* Mon Apr 19 2010 Jiri Popelka - 12:4.1.1-17 +- Fill in Elapsed Time Option in Release/Decline messages (#582939) + +* Thu Mar 25 2010 Jiri Popelka - 12:4.1.1-16 +- In client initiated message exchanges stop retransmission + upon reaching the MRD rather than at some point after it (#559153) + +* Wed Mar 24 2010 Jiri Popelka - 12:4.1.1-15 +- In dhclient-script check whether bound address + passed duplicate address detection (DAD) (#559147) +- If the bound address failed DAD (is found to be in use on the link), + the dhcpv6 client sends a Decline message to the server + as described in section 18.1.7 of RFC-3315 (#559147) + +* Fri Mar 19 2010 Jiri Popelka - 12:4.1.1-14 +- Fix UseMulticast.patch to not repeatedly parse dhcpd.conf for unicast option +- Fix dhclient-script to set interface MTU only when it's greater than 576 (#574629) + +* Fri Mar 12 2010 Jiri Popelka - 12:4.1.1-13 +- Discard unicast Request/Renew/Release/Decline message + (unless we set unicast option) and respond with Reply + with UseMulticast Status Code option (#573090) +- Remove DHCPV6 OPERATION section from dhclient.conf.5 + describing deprecated 'send dhcp6.oro' syntax + +* Thu Feb 25 2010 Jiri Popelka - 12:4.1.1-12 +- Fix paths in man pages (#568031) +- Remove odd tests in %%preun + +* Mon Feb 22 2010 Jiri Popelka - 12:4.1.1-11 +- Add interface-mtu to the list of default requested DHCP options (#566873) + +* Fri Feb 19 2010 Jiri Popelka - 12:4.1.1-10 +- Fix pm-utils/sleep.d/ directory ownership conflict + +* Fri Feb 19 2010 Jiri Popelka - 12:4.1.1-9 +- In dhclient-script: + - use ip command options '-4' or '-6' as shortcuts for '-f[amily] inet' resp. '-f[amily] inet6' + - do not use IP protocol family identifier with 'ip link' + +* Thu Feb 18 2010 Jiri Popelka - 12:4.1.1-8 +- Fix installation of pm-utils script (#479639, c#16) + +* Tue Feb 16 2010 Jiri Popelka - 12:4.1.1-7 +- ldap-for-dhcp-4.1.1-2 (#564810) + +* Tue Feb 16 2010 Jiri Popelka - 12:4.1.1-6 +- Fix ldap patch to explicitly link with liblber (#564810) + +* Mon Feb 08 2010 Jiri Popelka - 12:4.1.1-5 +- Fix dhclient-decline-backoff.patch (#562854) + +* Fri Feb 05 2010 Jiri Popelka - 12:4.1.1-4 +- Fix dhclient-script to delete address which the client is going to release + as soon as it begins the Release message exchange process (#559142) + +* Wed Feb 03 2010 Jiri Popelka - 12:4.1.1-3 +- move /etc/dhcp.conf to /etc/dhcp.conf.rpmsave in %%post (#561094) +- document -nc option in dhclient(8) man page + +* Tue Feb 02 2010 Jiri Popelka - 12:4.1.1-2 +- Fix capability patch (#546765) + +* Wed Jan 20 2010 Jiri Popelka - 12:4.1.1-1 +- Upgraded to ISC dhcp-4.1.1 + +* Mon Jan 18 2010 Jiri Popelka - 12:4.1.0p1-18 +- Hide startup info when starting dhcpd6 service. +- Remove -TERM from calling killproc when stopping dhcrelay (#555672) + +* Fri Jan 15 2010 Jiri Popelka - 12:4.1.0p1-17 +- Added init script to also start dhcpd for IPv6 (#552453) +- Added dhcpd6.conf.sample + +* Thu Jan 07 2010 Jiri Popelka - 12:4.1.0p1-16 +- Use %%global instead of %%define. + +* Mon Dec 14 2009 Jiri Popelka - 12:4.1.0p1-15 +- dhclient logs its pid to make troubleshooting NM managed systems + with multiple dhclients running easier (#546792) + +* Mon Nov 23 2009 Jiri Popelka - 12:4.1.0p1-14 +- Honor DEFROUTE=yes|no for all connection types (#530209) + +* Fri Oct 30 2009 Jiri Popelka - 12:4.1.0p1-13 +- Make dhclient-script add IPv6 address to interface (#531997) + +* Tue Oct 13 2009 Jiri Popelka - 12:4.1.0p1-12 +- Fix 56dhclient so network comes back after suspend/hibernate (#527641) + +* Thu Sep 24 2009 Jiri Popelka - 12:4.1.0p1-11 +- Make dhcpd and dhcrelay init scripts LSB compliant (#522134, #522146) + +* Mon Sep 21 2009 David Cantrell - 12:4.1.0p1-10 +- Obsolete the dhcpv6 and dhcpv6-client packages + +* Fri Sep 18 2009 David Cantrell - 12:4.1.0p1-9 +- Update dhclient-script with handlers for DHCPv6 states + +* Wed Aug 26 2009 David Cantrell - 12:4.1.0p1-8 +- Conditionalize restorecon calls in post scriptlets (#519479) + +* Wed Aug 26 2009 David Cantrell - 12:4.1.0p1-7 +- Do not require policycoreutils for post scriptlet (#519479) + +* Fri Aug 21 2009 David Cantrell - 12:4.1.0p1-6 +- BR libcap-ng-devel (#517649) + +* Tue Aug 18 2009 David Cantrell - 12:4.1.0p1-5 +- Drop unnecessary capabilities in dhclient (#517649) + +* Fri Aug 14 2009 David Cantrell - 12:4.1.0p1-4 +- Upgrade to latest ldap-for-dhcp patch which makes sure that only + dhcpd links with OpenLDAP (#517474) + +* Wed Aug 12 2009 David Cantrell - 12:4.1.0p1-3 +- Update NetworkManager dispatcher script to remove case conversion + and source /etc/sysconfig/network + +* Thu Aug 06 2009 David Cantrell - 12:4.1.0p1-2 +- Add /usr/lib[64]/pm-utils/sleep.d/56dhclient to handle suspend and + resume with active dhclient leases (#479639) + +* Wed Aug 05 2009 David Cantrell - 12:4.1.0p1-1 +- Upgrade to dhcp-4.1.0p1, which is the official upstream release to fix + CVE-2009-0692 + +* Wed Aug 05 2009 David Cantrell - 12:4.1.0-27 +- Fix for CVE-2009-0692 +- Fix for CVE-2009-1892 (#511834) + +* Fri Jul 24 2009 Fedora Release Engineering - 12:4.1.0-26 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu Jul 23 2009 David Cantrell - 12:4.1.0-25 +- Include NetworkManager dispatcher script to run dhclient.d scripts (#459276) + +* Thu Jul 09 2009 David Cantrell - 12:4.1.0-24 +- Ensure 64-bit platforms parse lease file dates & times correctly (#448615) + +* Thu Jul 09 2009 David Cantrell - 12:4.1.0-23 +- Upgrade to ldap-for-dhcp-4.1.0-4 + +* Wed Jul 01 2009 David Cantrell - 12:4.1.0-22 +- Set permissions on /etc/dhcp to 0750 (#508247) +- Update to new ldap-for-dhcp patch set +- Correct problems when upgrading from a previous release and your + dhcpd.conf file not being placed in /etc/dhcp (#506600) + +* Fri Jun 26 2009 David Cantrell - 12:4.1.0-21 +- Handle cases in add_timeout() where the function is called with a NULL + value for the 'when' parameter (#506626) +- Fix SELinux denials in dhclient-script when the script makes backup + configuration files and restores them later (#483747) + +* Wed May 06 2009 David Cantrell - 12:4.1.0-20 +- Obsolete libdhcp4client <= 12:4.0.0-34.fc10 (#499290) + +* Mon Apr 20 2009 David Cantrell - 12:4.1.0-19 +- Restrict interface names given on the dhcpd command line to length + IFNAMSIZ or shorter (#441524) +- Change to /etc/sysconfig/network-scripts in dhclient-script before + calling need_config or source_config (#496233) + +* Mon Apr 20 2009 David Cantrell - 12:4.1.0-18 +- Make dhclient-script work with pre-configured wireless interfaces (#491157) + +* Thu Apr 16 2009 David Cantrell - 12:4.1.0-17 +- Fix setting default route when client IP address changes (#486512, #473658) +- 'reload' and 'try-restart' on dhcpd and dhcrelay init scripts + will display usage information and return code 3 + +* Mon Apr 13 2009 David Cantrell - 12:4.1.0-16 +- Correct %%post problems in dhclient package (#495361) +- Read hooks scripts from /etc/dhcp (#495361) +- Update to latest ldap-for-dhcp + +* Fri Apr 03 2009 David Cantrell - 12:4.1.0-15 +- Obsolete libdhcp and libdhcp-devel (#493547) + +* Thu Apr 02 2009 David Cantrell - 12:4.1.0-14 +- Obsolete libdhcp and libdhcp-devel (#493547) + +* Tue Mar 31 2009 David Cantrell - 12:4.1.0-13 +- dhclient obsoletes libdhcp4client (#493213) +- dhcp-devel obsolets libdhcp4client-devel (#493213) + +* Wed Mar 11 2009 David Cantrell - 12:4.1.0-12 +- Fix problems with dhclient.d script execution (#488864) + +* Mon Mar 09 2009 David Cantrell - 12:4.1.0-11 +- Use LDAP configuration patch from upstream tarball + +* Thu Mar 05 2009 David Cantrell - 12:4.1.0-10 +- restorecon fixes for /etc/localtime and /etc/resolv.conf (#488470) + +* Tue Feb 24 2009 Fedora Release Engineering - 12:4.1.0-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Wed Feb 18 2009 David Cantrell - 12:4.1.0-8 +- Correct subsystem execution in dhclient-script (#486251) + +* Wed Feb 18 2009 David Cantrell - 12:4.1.0-7 +- Do not segfault if the ipv6 kernel module is not loaded (#486097) + +* Mon Feb 16 2009 David Cantrell - 12:4.1.0-6 +- Enable dhcpv6 support (#480798) +- Fix config file migration in scriptlets (#480543) +- Allow dhclient-script expansion with /etc/dhcp/dhclient.d/*.sh scripts + +* Thu Jan 15 2009 Tomas Mraz - 12:4.1.0-5 +- rebuild with new openssl + +* Tue Jan 13 2009 David Cantrell - 12:4.1.0-4 +- Updated LSB init script header to reference /etc/dhcp/dhcpd.conf (#479012) + +* Sun Jan 11 2009 David Cantrell - 12:4.1.0-3 +- Correct syntax errors in %%post script (#479012) + +* Sat Jan 10 2009 David Cantrell - 12:4.1.0-2 +- Make sure all /etc/dhcp config files are marked in the manifest +- Include new config file directies in the dhcp and dhclient packages +- Do not overwrite new config files if they already exist + +* Tue Jan 06 2009 David Cantrell - 12:4.1.0-1 +- Upgraded to ISC dhcp-4.1.0 +- Had to rename the -T option to -timeout as ISC is now using -T +- Allow package rebuilders to easily enable DHCPv6 support with: + rpmbuild --with DHCPv6 dhcp.spec + Note that Fedora is still using the 'dhcpv6' package, but some + users may want to experiment with the ISC DHCPv6 implementation + locally. + +* Thu Dec 18 2008 David Cantrell - 12:4.0.0-34 +- Move /etc/dhclient.conf to /etc/dhcp/dhclient.conf +- Move /etc/dhcpd.conf to /etc/dhcp/dhcpd.conf + +* Thu Dec 18 2008 David Cantrell - 12:4.0.0-33 +- Remove unnecessary success/failure lines in init scripts (#476846) + +* Wed Dec 03 2008 David Cantrell - 12:4.0.0-32 +- Enable LDAP/SSL support in dhcpd (#467740) +- Do not calculate a prefix for an address we did not receive (#473885) +- Removed libdhcp4client because libdhcp has been removed from Fedora + +* Wed Oct 29 2008 David Cantrell - 12:4.0.0-31 +- Use O_CLOEXEC in open(2) calls and "e" mode in fopen(3) calls, build + with -D_GNU_SOURCE so we pick up O_CLOEXEC (#468984) +- Add missing prototype for validate_port() in common/inet.c + +* Thu Oct 23 2008 David Cantrell - 12:4.0.0-30 +- Fix dhclient.conf man page and sample config file to say 'supersede + domain-search', which is what was actually demonstrated (#467955) + +* Wed Oct 01 2008 David Cantrell - 12:4.0.0-29 +- Make sure /etc/resolv.conf has restorecon run on it (#451560) + +* Tue Sep 30 2008 David Cantrell - 12:4.0.0-28 +- Forgot to actually include (#438149) + +* Tue Sep 30 2008 David Cantrell - 12:4.0.0-27 +- Fix patch fuzziness and include errno.h in includes/dhcpd.h (#438149) + +* Tue Sep 30 2008 David Cantrell - 12:4.0.0-26 +- Validate port numbers for dhclient, dhcpd, and dhcrelay to ensure + that are within the correct range (#438149) + +* Mon Sep 29 2008 David Cantrell - 12:4.0.0-25 +- Fix dhcpd so it can find configuration data via LDAP (#452985) + +* Tue Sep 16 2008 David Cantrell - 12:4.0.0-24 +- 'server' -> 'service' in dhclient-script (#462343) + +* Fri Aug 29 2008 David Cantrell - 12:4.0.0-23 +- Prevent $metric from being set to '' (#460640) +- Remove unnecessary warning messages +- Do not source config file (ifcfg-DEVICE) unless it exists + +* Sun Aug 24 2008 David Cantrell - 12:4.0.0-22 +- Add missing '[' to dhclient-script (#459860) +- Correct test statement in add_default_gateway() in dhclient-script (#459860) + +* Sat Aug 23 2008 David Cantrell - 12:4.0.0-21 +- Fix syntax error in dhclient-script (#459860) + +* Fri Aug 22 2008 David Cantrell - 12:4.0.0-20 +- Rewrite of /sbin/dhclient-script (make the script a little more readable, + discontinue use of ifconfig in favor of ip, store backup copies of orig + files in /var rather than in /etc) + +* Wed Aug 06 2008 David Cantrell - 12:4.0.0-19 +- Remove 'c' from the domain-search format string in common/tables.c +- Prevent \032 from appearing in resolv.conf search line (#450042) +- Restore SELinux context on saved /etc files (#451560) + +* Sun Aug 03 2008 Tom "spot" Callaway - 12:4.0.0-18 +- filter out false positive perl requires + +* Fri Aug 01 2008 David Cantrell - 12:4.0.0-17 +- Carry over RES_OPTIONS from ifcfg-ethX files to /etc/resolv.conf (#202923) +- Clean up Requires tags for devel packages +- Allow SEARCH variable in ifcfg files to override search path (#454152) +- Do not down interface if there is an active lease (#453982) +- Clean up how dhclient-script restarts ypbind +- Set close-on-exec on dhclient.leases for SELinux (#446632) + +* Sat Jun 21 2008 David Cantrell - 12:4.0.0-16 +- Remove instaces of \032 in domain search option (#450042) +- Make 'service dhcpd configtest' display text indicating the status + +* Fri May 16 2008 David Cantrell - 12:4.0.0-15 +- Set close-on-exec on dhclient.leases for SELinux (#446632) + +* Tue Apr 01 2008 David Cantrell - 12:4.0.0-14 +- Avoid dhclient crash when run via NetworkManager (#439796) + +* Tue Mar 25 2008 David Cantrell - 12:4.0.0-13 +- Update dhclient-script to handle domain-search correctly (#437840) + +* Tue Mar 25 2008 David Cantrell - 12:4.0.0-12 +- Remove Requires on openldap-server (#432180) +- Replace CLIENTBINDIR, ETCDIR, DBDIR, and RUNDIR in the man pages with the + correct paths + +* Wed Feb 13 2008 David Cantrell - 12:4.0.0-11 +- Add missing newline to usage() screen in dhclient + +* Thu Feb 07 2008 David Cantrell - 12:4.0.0-10 +- Save conf files adding '.predhclient.$interface' to the name (#306381) +- Only restore conf files on EXPIRE/FAIL/RELEASE/STOP if there are no other + dhclient processes running (#306381) + +* Wed Feb 06 2008 David Cantrell - 12:4.0.0-9 +- Match LDAP server option values in stables.c and dhcpd.h (#431003) +- Fix invalid sprintf() statement in server/ldap.c (#431003) + +* Wed Feb 06 2008 David Cantrell - 12:4.0.0-8 +- Remove invalid fclose() patch + +* Tue Feb 05 2008 David Cantrell - 12:4.0.0-7 +- Don't leak /var/lib/dhclient/dhclient.leases file descriptors (#429890) + +* Tue Jan 22 2008 David Cantrell - 12:4.0.0-6 +- read_function() comes from the LDAP patch, so fix it there +- Init new struct universe structs in libdhcp4client so we don't crash on + multiple DHCP attempts (#428203) + +* Thu Jan 17 2008 David Cantrell - 12:4.0.0-5 +- Patch read_function() to handle size_t from read() correctly (#429207) + +* Wed Jan 16 2008 David Cantrell - 12:4.0.0-4 +- Fix dhclient.lease file parsing problems (#428785) +- Disable IPv6 support for now as we already ship dhcpv6 (#428987) + +* Tue Jan 15 2008 David Cantrell - 12:4.0.0-3 +- Fix segfault in next_iface4() and next_iface6() (#428870) + +* Mon Jan 14 2008 David Cantrell - 12:4.0.0-2 +- -fvisibility fails me again + +* Mon Jan 14 2008 David Cantrell - 12:4.0.0-1 +- Upgrade to ISC dhcp-4.0.0 (#426634) + - first ISC release to incorporate DHCPv6 protocol support + - source tree now uses GNU autoconf/automake +- Removed the libdhcp4client-static package +