From cc45fbd76ed54efda7538a2eb8e56dd714346467 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Mon, 18 Aug 2008 12:43:05 +0000 Subject: [PATCH] The require directive now requires that the required options are present in each DHCP message. A few variables and functions have also been renamed to make this part more readable. --- client.c | 12 +++++++++++- dhcp.c | 16 ++++++++-------- dhcp.h | 8 ++++---- dhcpcd.8.in | 7 ++++++- dhcpcd.c | 48 +++++++++++++++++++++++++++++------------------- dhcpcd.conf.5.in | 16 ++++++++++++---- dhcpcd.h | 3 ++- 7 files changed, 72 insertions(+), 38 deletions(-) diff --git a/client.c b/client.c index 7d23c391..18be14aa 100644 --- a/client.c +++ b/client.c @@ -1357,7 +1357,7 @@ handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp, struct dhcp_message *dhcp = *dhcpp; struct interface *iface = state->interface; struct dhcp_lease *lease = &state->lease; - uint8_t type; + uint8_t type, tmp; struct in_addr addr; size_t i; int r; @@ -1415,6 +1415,16 @@ handle_dhcp(struct if_state *state, struct dhcp_message **dhcpp, /* No NAK, so reset the backoff */ state->nakoff = 1; + /* Ensure that all required options are present */ + for (i = 1; i < 255; i++) { + if (has_option_mask(options->requiremask, i) && + get_option_uint8(&tmp, dhcp, i) != 0) + { + log_dhcp(LOG_WARNING, "reject", dhcp); + return 0; + } + } + if (type == DHCP_OFFER && state->state == STATE_DISCOVERING) { lease->addr.s_addr = dhcp->yiaddr; get_option_addr(&lease->server.s_addr, dhcp, DHO_SERVERID); diff --git a/dhcp.c b/dhcp.c index 460d7c5f..a9ef632c 100644 --- a/dhcp.c +++ b/dhcp.c @@ -166,7 +166,7 @@ print_options(void) printf("%03d %s\n", opt->option, opt->var); } -int make_reqmask(uint8_t *mask, char **opts, int add) +int make_option_mask(uint8_t *mask, char **opts, int add) { char *token, *p = *opts, *t; const struct dhcp_opt *opt; @@ -190,11 +190,11 @@ int make_reqmask(uint8_t *mask, char **opts, int add) } if (match) { if (add == 1) - add_reqmask(mask, - opt->option); + add_option_mask(mask, + opt->option); else - del_reqmask(mask, - opt->option); + del_option_mask(mask, + opt->option); break; } } @@ -908,7 +908,7 @@ make_message(struct dhcp_message **message, *p++ = 0; for (opt = dhcp_opts; opt->option; opt++) { if (!(opt->type & REQUEST || - has_reqmask(options->reqmask, opt->option))) + has_option_mask(options->requestmask, opt->option))) continue; switch (opt->option) { case DHO_RENEWALTIME: /* FALLTHROUGH */ @@ -1176,7 +1176,7 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp, for (opt = dhcp_opts; opt->option; opt++) { if (!opt->var) continue; - if (has_reqmask(options->nomask, opt->option)) + if (has_option_mask(options->nomask, opt->option)) continue; if (get_option_raw(dhcp, opt->option)) e++; @@ -1219,7 +1219,7 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp, for (opt = dhcp_opts; opt->option; opt++) { if (!opt->var) continue; - if (has_reqmask(options->nomask, opt->option)) + if (has_option_mask(options->nomask, opt->option)) continue; val = NULL; p = get_option(dhcp, opt->option, &pl, NULL); diff --git a/dhcp.h b/dhcp.h index f135f649..e584452c 100644 --- a/dhcp.h +++ b/dhcp.h @@ -154,10 +154,10 @@ struct dhcp_lease { uint8_t frominfo; }; -#define add_reqmask(var, val) (var[val >> 3] |= 1 << (val & 7)) -#define del_reqmask(var, val) (var[val >> 3] &= ~(1 << (val & 7))) -#define has_reqmask(var, val) (var[val >> 3] & (1 << (val & 7))) -int make_reqmask(uint8_t *, char **, int); +#define add_option_mask(var, val) (var[val >> 3] |= 1 << (val & 7)) +#define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7))) +#define has_option_mask(var, val) (var[val >> 3] & (1 << (val & 7))) +int make_option_mask(uint8_t *, char **, int); void print_options(void); char *get_option_string(const struct dhcp_message *, uint8_t); int get_option_addr(uint32_t *, const struct dhcp_message *, uint8_t); diff --git a/dhcpcd.8.in b/dhcpcd.8.in index 90586310..993a4c08 100644 --- a/dhcpcd.8.in +++ b/dhcpcd.8.in @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 13, 2008 +.Dd August 18, 2008 .Dt DHCPCD 8 SMM .Sh NAME .Nm dhcpcd @@ -46,6 +46,7 @@ .Op Fl F , -fqdn Ar FQDN .Op Fl I , -clientid Ar clientid .Op Fl O , -nooption Ar option +.Op Fl Q , -require Ar option .Op Fl X , -blacklist Ar address .Ar interface .Nm @@ -351,6 +352,10 @@ Don't use IPv4LL (aka APIPA, aka Bonjour, aka ZeroConf). Don't request the specified option. If no option given, then don't request any options other than those to configure the interface and routing. +.It Fl Q , -require Ar option +Requires the +.Ar option +to be present in all DHCP messages, otherwise the message is ignored. .It Fl T, -test On receipt of OFFER messages just call .Pa @SCRIPT@ diff --git a/dhcpcd.c b/dhcpcd.c index 3cd02b0d..c32ffd92 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -53,7 +53,7 @@ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples"; /* Don't set any optional arguments here so we retain POSIX * compatibility with getopt */ -#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xABC:DEF:GI:KLO:TVX:" +#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xABC:DEF:GI:KLO:Q:TVX:" static int doversion = 0; static int dohelp = 0; @@ -88,6 +88,7 @@ static const struct option longopts[] = { {"nolink", no_argument, NULL, 'K'}, {"noipv4ll", no_argument, NULL, 'L'}, {"nooption", optional_argument, NULL, 'O'}, + {"require", required_argument, NULL, 'Q'}, {"test", no_argument, NULL, 'T'}, {"variables", no_argument, NULL, 'V'}, {"blacklist", required_argument, NULL, 'X'}, @@ -154,7 +155,7 @@ usage(void) printf("usage: "PACKAGE" [-dknpqxADEGHKLOTV] [-c script] [-f file ] [-h hostname]\n" " [-i classID ] [-l leasetime] [-m metric] [-o option] [-r ipaddr]\n" " [-s ipaddr] [-t timeout] [-u userclass] [-F none|ptr|both]\n" - " [-I clientID] [-C hookscript] [-X ipaddr] \n"); + " [-I clientID] [-C hookscript] [-Q option] [-X ipaddr] \n"); } static char * @@ -361,7 +362,7 @@ parse_option(int opt, char *oarg, struct options *options) } break; case 'o': - if (make_reqmask(options->reqmask, &oarg, 1) != 0) { + if (make_option_mask(options->requestmask, &oarg, 1) != 0) { logger(LOG_ERR, "unknown option `%s'", oarg); return -1; } @@ -531,13 +532,22 @@ parse_option(int opt, char *oarg, struct options *options) options->options &= ~DHCPCD_IPV4LL; break; case 'O': - if (make_reqmask(options->reqmask, &optarg, -1) != 0 || - make_reqmask(options->nomask, &optarg, 1) != 0) + if (make_option_mask(options->requestmask, &oarg, -1) != 0 || + make_option_mask(options->requiremask, &oarg, -1) != 0 || + make_option_mask(options->nomask, &oarg, 1) != 0) { logger(LOG_ERR, "unknown option `%s'", optarg); return -1; } break; + case 'Q': + if (make_option_mask(options->requiremask, &oarg, 1) != 0 || + make_option_mask(options->requestmask, &oarg, 1) != 0) + { + logger(LOG_ERR, "unknown option `%s'", oarg); + return -1; + } + break; case 'X': if (!inet_aton(oarg, &addr)) { logger(LOG_ERR, "`%s' is not a valid IP address", @@ -617,12 +627,12 @@ main(int argc, char **argv) "%s %s", PACKAGE, VERSION); #ifdef CMDLINE_COMPAT - add_reqmask(options->reqmask, DHO_DNSSERVER); - add_reqmask(options->reqmask, DHO_DNSDOMAIN); - add_reqmask(options->reqmask, DHO_DNSSEARCH); - add_reqmask(options->reqmask, DHO_NISSERVER); - add_reqmask(options->reqmask, DHO_NISDOMAIN); - add_reqmask(options->reqmask, DHO_NTPSERVER); + add_requestmask(options->requestmask, DHO_DNSSERVER); + add_requestmask(options->reqmask, DHO_DNSDOMAIN); + add_requestmask(options->reqmask, DHO_DNSSEARCH); + add_requestmask(options->reqmask, DHO_NISSERVER); + add_requestmask(options->reqmask, DHO_NISDOMAIN); + add_requestmask(options->reqmask, DHO_NTPSERVER); /* If the duid file exists, then enable duid by default * This means we don't break existing clients that easily :) */ @@ -771,22 +781,22 @@ main(int argc, char **argv) #ifdef CMDLINE_COMPAT case 'H': /* FALLTHROUGH */ case 'M': - del_reqmask(options->reqmask, DHO_MTU); + del_requestmask(options->reqmask, DHO_MTU); break; case 'N': - del_reqmask(options->reqmask, DHO_NTPSERVER); + del_requestmask(options->reqmask, DHO_NTPSERVER); break; case 'R': - del_reqmask(options->reqmask, DHO_DNSSERVER); - del_reqmask(options->reqmask, DHO_DNSDOMAIN); - del_reqmask(options->reqmask, DHO_DNSSEARCH); + del_requestmask(options->reqmask, DHO_DNSSERVER); + del_requestmask(options->reqmask, DHO_DNSDOMAIN); + del_requestmask(options->reqmask, DHO_DNSSEARCH); break; case 'S': - add_reqmask(options->reqmask, DHO_MSCSR); + add_requestmask(options->reqmask, DHO_MSCSR); break; case 'Y': - del_reqmask(options->reqmask, DHO_NISSERVER); - del_reqmask(options->reqmask, DHO_NISDOMAIN); + del_requestmask(options->reqmask, DHO_NISSERVER); + del_requestmask(options->reqmask, DHO_NISDOMAIN); break; #endif default: diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in index f58c087f..899aea35 100644 --- a/dhcpcd.conf.5.in +++ b/dhcpcd.conf.5.in @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 17, 2008 +.Dd August 18, 2008 .Dt DHCPCD.CONF 5 SMM .Sh NAME .Nm dhcpcd.conf @@ -103,14 +103,22 @@ See .It Ic nolink Don't receive link messages about carrier status. You should only set this for buggy interface drivers. -.It Ic option Ar dhcp-option +.It Ic option Ar option Requests the -.Ar dhcp-option +.Ar option from the server. It can be a variable to be used in .Xr dhcpcd-run-hooks 8 or the numerical value. -You can specify more seperated by commas, spaces or more option lines. +You can specify more options seperated by commas, spaces or more option lines. +.It Ic require Ar option +Requires the +.Ar option +to be present in all DHCP messages, otherwise the message is ignored. +It can be a variable to be used in +.Xr dhcpcd-run-hooks 8 +or the numerical value. +You can specify more options seperated by commas, spaces or more require lines. .It Ic script Ar script Use .Ar script diff --git a/dhcpcd.h b/dhcpcd.h index dc7cff41..1cd2b5d5 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -68,7 +68,8 @@ struct options { char interface[IF_NAMESIZE]; int metric; - uint8_t reqmask[256 / 8]; + uint8_t requestmask[256 / 8]; + uint8_t requiremask[256 / 8]; uint8_t nomask[256 / 8]; uint32_t leasetime; time_t timeout;