diff --git a/0001-change-bug-url.patch b/0001-change-bug-url.patch new file mode 100644 index 0000000000000000000000000000000000000000..d0edd1b07830844c834c140028a7db8fb2c10b9c --- /dev/null +++ b/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.openanolis.cn/"); ++ ++ 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/0002-additional-dhclient-options.patch b/0002-additional-dhclient-options.patch new file mode 100644 index 0000000000000000000000000000000000000000..d700c004cce1b360c0c8490b85955151f6f76618 --- /dev/null +++ b/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/0003-Handle-releasing-interfaces-requested-by-sbin-ifup.patch b/0003-Handle-releasing-interfaces-requested-by-sbin-ifup.patch new file mode 100644 index 0000000000000000000000000000000000000000..2953c0fbcb19db7199af35c6e0f4a3042e12b9d7 --- /dev/null +++ b/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/0004-Support-unicast-BOOTP-for-IBM-pSeries-systems-and-ma.patch b/0004-Support-unicast-BOOTP-for-IBM-pSeries-systems-and-ma.patch new file mode 100644 index 0000000000000000000000000000000000000000..7f414a30f9f4c66120690045f3b612f73cf32b65 --- /dev/null +++ b/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/0005-Change-default-requested-options.patch b/0005-Change-default-requested-options.patch new file mode 100644 index 0000000000000000000000000000000000000000..34ff7b50d377ac0c5c990e70c6ef8ba80f1aa805 --- /dev/null +++ b/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/0006-Various-man-page-only-fixes.patch b/0006-Various-man-page-only-fixes.patch new file mode 100644 index 0000000000000000000000000000000000000000..a98783c432bae8b31955182478b72b7b99d4f6ce --- /dev/null +++ b/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/0007-Change-paths-to-conform-to-our-standards.patch b/0007-Change-paths-to-conform-to-our-standards.patch new file mode 100644 index 0000000000000000000000000000000000000000..87c4f8cd40e4c0ffa43761b9e583947f5149da9a --- /dev/null +++ b/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/0008-Make-sure-all-open-file-descriptors-are-closed-on-ex.patch b/0008-Make-sure-all-open-file-descriptors-are-closed-on-ex.patch new file mode 100644 index 0000000000000000000000000000000000000000..829456360d8ba5e17bf878005838fca8872ce2ae --- /dev/null +++ b/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/0009-Fix-garbage-in-format-string-error.patch b/0009-Fix-garbage-in-format-string-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..f9d81ab7b47d57c9706132c1f234b101b0fb598d --- /dev/null +++ b/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/0010-Handle-null-timeout.patch b/0010-Handle-null-timeout.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b6e49b570bec1c805da1abc8e88d2c4243a3f78 --- /dev/null +++ b/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/0011-Drop-unnecessary-capabilities.patch b/0011-Drop-unnecessary-capabilities.patch new file mode 100644 index 0000000000000000000000000000000000000000..cfb055ed2379c448bfd3cd423bb3830a7fba9b16 --- /dev/null +++ b/0011-Drop-unnecessary-capabilities.patch @@ -0,0 +1,276 @@ +From 3863afcdfc5996f25741a41272c1a3bea0476692 Mon Sep 17 00:00:00 2001 +From: Pavel Zhukov +Date: Thu, 21 Feb 2019 10:30:28 +0100 +Subject: [PATCH] Drop unnecessary capabilities + +dhclient (#517649, #546765), dhcpd/dhcrelay (#699713) +--- + client/Makefile.am | 3 ++- + client/dhclient-script.8 | 10 ++++++++++ + client/dhclient.8 | 29 +++++++++++++++++++++++++++++ + client/dhclient.c | 24 ++++++++++++++++++++++++ + configure.ac | 35 +++++++++++++++++++++++++++++++++++ + relay/Makefile.am | 3 ++- + relay/dhcrelay.c | 29 +++++++++++++++++++++++++++++ + 7 files changed, 131 insertions(+), 2 deletions(-) + +diff --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 7155cc5..9f1e435 100644 +--- a/client/dhclient.8 ++++ b/client/dhclient.8 +@@ -135,6 +135,9 @@ dhclient - Dynamic Host Configuration Protocol Client + .B -w + ] + [ ++.B -nc ++] ++[ + .B -B + ] + [ +@@ -329,6 +332,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 adcce50..7f202f9 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. +@@ -271,6 +275,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)); +@@ -670,6 +677,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) { +@@ -730,6 +741,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 2ca53ff..3276888 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -603,6 +603,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 5562b69..4c5cfa6 100644 +--- a/relay/Makefile.am ++++ b/relay/Makefile.am +@@ -8,6 +8,7 @@ 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 5e4a6a9..4c472a9 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]; +@@ -597,6 +602,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) +@@ -667,6 +676,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); +@@ -823,6 +843,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.31.1 + diff --git a/0012-RFC-3442-Classless-Static-Route-Option-for-DHCPv4-51.patch b/0012-RFC-3442-Classless-Static-Route-Option-for-DHCPv4-51.patch new file mode 100644 index 0000000000000000000000000000000000000000..866527c2260f3aed1e0398e3988459ad1550c864 --- /dev/null +++ b/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/0013-DHCPv6-over-PPP-support-626514.patch b/0013-DHCPv6-over-PPP-support-626514.patch new file mode 100644 index 0000000000000000000000000000000000000000..5e0a6bab7593d67bb114a027afc3998829d19352 --- /dev/null +++ b/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/0014-IPoIB-support-660681.patch b/0014-IPoIB-support-660681.patch new file mode 100644 index 0000000000000000000000000000000000000000..3d6d316f1afcf091772eb533b931cc5808727241 --- /dev/null +++ b/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/0015-Add-GUID-DUID-to-dhcpd-logs-1064416.patch b/0015-Add-GUID-DUID-to-dhcpd-logs-1064416.patch new file mode 100644 index 0000000000000000000000000000000000000000..1f88d7d99686b762280e62e345b2f7a434a3be93 --- /dev/null +++ b/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/0016-Turn-on-creating-sending-of-DUID.patch b/0016-Turn-on-creating-sending-of-DUID.patch new file mode 100644 index 0000000000000000000000000000000000000000..bafffb5a18b80e08b80d9d62dc2a09d6eb9304b7 --- /dev/null +++ b/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/0017-Send-unicast-request-release-via-correct-interface.patch b/0017-Send-unicast-request-release-via-correct-interface.patch new file mode 100644 index 0000000000000000000000000000000000000000..26c8b9655abb732e0ca37d6d7018209b8bea1633 --- /dev/null +++ b/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/0018-No-subnet-declaration-for-iface-should-be-info-not-e.patch b/0018-No-subnet-declaration-for-iface-should-be-info-not-e.patch new file mode 100644 index 0000000000000000000000000000000000000000..2ff4030ef999d708f5a81639daf730526a57bef4 --- /dev/null +++ b/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/0019-dhclient-write-DUID_LLT-even-in-stateless-mode-11563.patch b/0019-dhclient-write-DUID_LLT-even-in-stateless-mode-11563.patch new file mode 100644 index 0000000000000000000000000000000000000000..3405ea13bd5a038601bf50806451d2fa6c4ac0ce --- /dev/null +++ b/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/0020-Discover-all-hwaddress-for-xid-uniqueness.patch b/0020-Discover-all-hwaddress-for-xid-uniqueness.patch new file mode 100644 index 0000000000000000000000000000000000000000..c838d7ac9ba919c23bfad7a69085c3cfb0d0c49b --- /dev/null +++ b/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/0021-Load-leases-DB-in-non-replay-mode-only.patch b/0021-Load-leases-DB-in-non-replay-mode-only.patch new file mode 100644 index 0000000000000000000000000000000000000000..d3989183b69686a0ff937e02fc94eabaa7852217 --- /dev/null +++ b/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/0022-dhclient-make-sure-link-local-address-is-ready-in-st.patch b/0022-dhclient-make-sure-link-local-address-is-ready-in-st.patch new file mode 100644 index 0000000000000000000000000000000000000000..85ea650688ca5a4f7c7fe36ad21e7d618f43abc6 --- /dev/null +++ b/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/0023-option-97-pxe-client-id.patch b/0023-option-97-pxe-client-id.patch new file mode 100644 index 0000000000000000000000000000000000000000..6cc432893f8905efc0662a730684f0acedc95142 --- /dev/null +++ b/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/0024-Detect-system-time-changes.patch b/0024-Detect-system-time-changes.patch new file mode 100644 index 0000000000000000000000000000000000000000..cf38d0d7239888a81423fb58e594750d42abd55b --- /dev/null +++ b/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/0025-bind-Detect-system-time-changes.patch b/0025-bind-Detect-system-time-changes.patch new file mode 100644 index 0000000000000000000000000000000000000000..80191b26c90e6fa1d7e5412605da18c75985f0a6 --- /dev/null +++ b/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/0026-Add-dhclient-5-B-option-description.patch b/0026-Add-dhclient-5-B-option-description.patch new file mode 100644 index 0000000000000000000000000000000000000000..7ddfacf55e0e115353f6c0434ea61b574fd29f60 --- /dev/null +++ b/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/0027-Add-missed-sd-notify-patch-to-manage-dhcpd-with-syst.patch b/0027-Add-missed-sd-notify-patch-to-manage-dhcpd-with-syst.patch new file mode 100644 index 0000000000000000000000000000000000000000..cde51de58b299d93e5bc148f7b7dd6985524f786 --- /dev/null +++ b/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/0029-Use-system-getaddrinfo-for-dhcp.patch b/0029-Use-system-getaddrinfo-for-dhcp.patch new file mode 100644 index 0000000000000000000000000000000000000000..24cbb6be72fb68698ceab09ab87a8eec67cc64a5 --- /dev/null +++ b/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/11-dhclient b/11-dhclient new file mode 100644 index 0000000000000000000000000000000000000000..8bd0c75d979f00f6b0f37b82ec0ef143febe5010 --- /dev/null +++ b/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/56dhclient b/56dhclient new file mode 100644 index 0000000000000000000000000000000000000000..7f185f10f49179011612fbb826cc5631ab9b6b3b --- /dev/null +++ b/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/README.dhclient.d b/README.dhclient.d new file mode 100644 index 0000000000000000000000000000000000000000..6899aaa86b65382166640aa7bbabb6324e6f38db --- /dev/null +++ b/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/codesign2021.txt b/codesign2021.txt new file mode 100644 index 0000000000000000000000000000000000000000..d021b564512488bfecbd6a0083affd51d51f92d6 --- /dev/null +++ b/codesign2021.txt @@ -0,0 +1,534 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=fX+D +-----END PGP PUBLIC KEY BLOCK----- +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +4xcYgqlVpv15O7VrD+I= +=Uugw +-----END PGP PUBLIC KEY BLOCK----- diff --git a/dhclient-script b/dhclient-script new file mode 100644 index 0000000000000000000000000000000000000000..5f5811299795675bb619dcc539fd7890804f04e8 --- /dev/null +++ b/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/dhcp-4.4.2-P1.tar.gz b/dhcp-4.4.2-P1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..e1a084a759c89028203f51039b5d14a42f77f035 Binary files /dev/null and b/dhcp-4.4.2-P1.tar.gz differ diff --git a/dhcp-4.4.2-P1.tar.gz.asc b/dhcp-4.4.2-P1.tar.gz.asc new file mode 100644 index 0000000000000000000000000000000000000000..bdda35073d1ffeb00b49c152b88b865e8749f0b7 --- /dev/null +++ b/dhcp-4.4.2-P1.tar.gz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABAgAdFiEEJFV3TUL9/mucOD64/hACvFlwgR8FAmClcL0ACgkQ/hACvFlw +gR8x7g/8CWUqsUBmN9aMsoqsZKvcR4Yqi+vl+VvpkUVdJxLWKBonTnQ544U8b4qq +GDwfht5LKCUSjF15fNxfbztkTFnxW3CnWmE25HsZwfVOGrBfPRHwO/BvmerqTBui +JPWOVsauwSp1KbEsxJUZERUZO1CncHdrxJ5bk8lPD25/QgxHVQzdxRwkml1uBlI4 +6wF9in05HK+GwZi5G5E7YrNDZKnCk2qtndCeAhlpl0zLUiImVP7EbDZRRpczyQqK +ZpWRpsFLeGCPWAWeomj0EG+S9nxS6UjVq0BS6kMrVTcwfIK1U9OkZRgYLMIkEV5y +vpu1tjXDZxU4lnGtUkQgjnGxWvnldMohvKDYUvKBOyomnYOpMZhMtLTmZRUk0oBz +8vLPK59BQGFsrQw/gA46+jM7oahrZp/uVx4WJkyzjuoZ41N3y61fOgZzMkFwt9wc +F08k66S4fTxxVpnAwMNVn7C7D7IMlCpuVG7/jB50Go9NsaY8Q8FcDxnqrNETNfPC +PZzgM+IkhPOaZezP36UPv9v/ME0sz9YEzslxKtsf2rsoXT0iS/vTuHryyZpfuvks +F7JZk9JlHkG+eoY1h/g05RtC+z+n3U5dn+pIETd9o3OgBYlJXaxA4E1LbkzrfqJC +icxx7sx4/e93/wUd7xppTwk3/+F9Yzp6qrIZDNWIzNWCxKytvdE= +=bHZP +-----END PGP SIGNATURE----- diff --git a/dhcp.spec b/dhcp.spec new file mode 100644 index 0000000000000000000000000000000000000000..b56005c61b82dabb8ea31cfe2fdf73ff1d6ac261 --- /dev/null +++ b/dhcp.spec @@ -0,0 +1,506 @@ +%define anolis_release 1 +# disable systemtap +%{!?sdt:%global sdt 0} + +%global _hardened_build 1 +%global dhcpconfdir %{_sysconfdir}/dhcp +%global patchver P1 +%global DHCPVERSION %{version}%{?prever}%{?patchver:-%{patchver}} + +Summary: Dynamic host configuration protocol software +Name: dhcp +Version: 4.4.2 +Release: %{anolis_release}%{?prever:.%prever}%{?patchver:.%patchver}%{?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 and MPLv2.0 +Url: https://www.isc.org/dhcp/ +Source0: https://downloads.isc.org/isc/dhcp/%{DHCPVERSION}/dhcp-%{DHCPVERSION}.tar.gz +Source9: https://downloads.isc.org/isc/dhcp/%{DHCPVERSION}/dhcp-%{DHCPVERSION}.tar.gz.asc +Source10: codesign2021.txt +Source1: dhclient-script +Source2: README.dhclient.d +Source3: 11-dhclient +Source5: 56dhclient +Source6: dhcpd.service +Source7: dhcpd6.service +Source8: dhcrelay.service + +# backend compat and borrowed from rhel +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 +Patch29: 0029-Use-system-getaddrinfo-for-dhcp.patch + +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: make +BuildRequires: libtool +BuildRequires: openldap-devel +BuildRequires: krb5-devel +BuildRequires: libcap-ng-devel +BuildRequires: systemd systemd-devel +BuildRequires: pkgconfig(libsystemd) +BuildRequires: gnupg2 +BuildRequires: doxygen +%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} +Obsoletes: %{name}-compat < 12:4.4.2-12.b1 +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} +Obsoletes: %{name}-compat < 12:4.4.2-12.b1 +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. + +%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. + +%prep +%{gpgverify} --keyring='%{SOURCE10}' --signature='%{SOURCE9}' --data='%{SOURCE0}' +%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 + +pushd doc +make %{?_smp_mflags} devel +popd + +%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 + +%files devel-doc +%doc doc/html/ + +%changelog +* Wed Mar 09 2022 Chunmei Xu - 12:4.4.2-1.P1 +- init from upstream 4.4.2.p1 +- add patches to keep backend compat diff --git a/dhcpd.service b/dhcpd.service new file mode 100644 index 0000000000000000000000000000000000000000..7363d7d4216c7485dca114a26ac31fbbac660681 --- /dev/null +++ b/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/dhcpd6.service b/dhcpd6.service new file mode 100644 index 0000000000000000000000000000000000000000..ff844c0bd30aab48e57b0d93a5f21d829c89c609 --- /dev/null +++ b/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/dhcrelay.service b/dhcrelay.service new file mode 100644 index 0000000000000000000000000000000000000000..43a0ca3776ebb4c8c9a51d86b13b1bc14f9d7e2c --- /dev/null +++ b/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