{ DHCP_MTU, OPT_UINT16R, "MTU" },
{ DHCP_STATICROUTE, OPT_IPV4R, NULL },
{ DHCP_ROUTER, OPT_IPV4R, NULL },
- { DHCP_HOSTNAME, OPT_STRINGR, "HOSTNAME" },
- { DHCP_DNSSERVER, OPT_IPV4R, "DNSSERVER" },
- { DHCP_DNSDOMAIN, OPT_STRINGR, "DNSDOMAIN" },
- { DHCP_DNSSEARCH, OPT_STRINGR | OPT_RFC3397, "DNSSEARCH" },
- { DHCP_NTPSERVER, OPT_IPV4R, "NTPSERVER" },
- { DHCP_NISSERVER, OPT_IPV4R, "NISSERVER" },
- { DHCP_NISDOMAIN, OPT_IPV4R, "NISDOMAIN" },
- { DHCP_ROOTPATH, OPT_STRINGR, "ROOTPATH" },
- { DHCP_SIPSERVER, OPT_STRINGR | OPT_RFC3361, "SIPSERVER" },
+ { DHCP_HOSTNAME, OPT_STRING, "HOSTNAME" },
+ { DHCP_DNSSERVER, OPT_IPV4, "DNSSERVER" },
+ { DHCP_DNSDOMAIN, OPT_STRING, "DNSDOMAIN" },
+ { DHCP_DNSSEARCH, OPT_STRING | OPT_RFC3397, "DNSSEARCH" },
+ { DHCP_NTPSERVER, OPT_IPV4, "NTPSERVER" },
+ { DHCP_NISSERVER, OPT_IPV4, "NISSERVER" },
+ { DHCP_NISDOMAIN, OPT_IPV4, "NISDOMAIN" },
+ { DHCP_ROOTPATH, OPT_STRING, "ROOTPATH" },
+ { DHCP_SIPSERVER, OPT_STRING | OPT_RFC3361, "SIPSERVER" },
{ DHCP_MESSAGE, OPT_STRING, NULL},
{ 0, 0, NULL }
};
+int make_reqmask(struct options *options, char **opts)
+{
+ char *token;
+ char *p = *opts;
+ uint8_t i;
+ const char *v;
+ int max = sizeof(dhcp_options) / sizeof(dhcp_options[0]);
+
+ while ((token = strsep(&p, ","))) {
+ for (i = 0; i < max; i++) {
+ if (!(v = dhcp_options[i].var))
+ continue;
+ if (strcmp(v, token) == 0) {
+ add_reqmask(options->reqmask,
+ dhcp_options[i].option);
+ break;
+ }
+ }
+ if (i >= max) {
+ *opts = token;
+ errno = ENOENT;
+ return -1;
+ }
+ }
+ return 0;
+}
+
static int
valid_length(uint8_t option, const uint8_t *data, int *type)
{
time_t up = uptime() - iface->start_uptime;
uint32_t ul;
uint16_t sz;
+ uint8_t o;
dhcp = xzalloc(sizeof (*dhcp));
m = (uint8_t *)dhcp;
n_params = p;
*p++ = 0;
for (l = 0; l < sizeof(dhcp_options) / sizeof(dhcp_options[0]); l++) {
- if (!(dhcp_options[l].type & OPT_REQUEST))
+ o = dhcp_options[l].option;
+ if (!(dhcp_options[l].type & OPT_REQUEST) &&
+ !has_reqmask(options->reqmask, o))
continue;
- switch (dhcp_options[l].option) {
+ switch (o) {
case DHCP_RENEWALTIME: /* FALLTHROUGH */
case DHCP_REBINDTIME:
if (type == DHCP_INFORM)
continue;
break;
}
- *p++ = dhcp_options[l].option;
+ *p++ = o;
}
if (options->domscsr)
*p++ = DHCP_MSCSR;
uint8_t frominfo;
};
+#define add_reqmask(var, val) (var[val >> 3] |= 1 << (val & 7))
+#define has_reqmask(var, val) (var[val >> 3] & (1 << (val & 7)))
+int make_reqmask(struct options *options, char **opts);
const uint8_t *get_option(const struct dhcp_message *, uint8_t);
char *get_option_string(const struct dhcp_message *, uint8_t);
int get_option_addr(uint32_t *a, const struct dhcp_message *dhcp, uint8_t option);
.Nd an RFC 2131 compliant DHCP client
.Sh SYNOPSIS
.Nm
-.Op Fl dknpAEGHMLNRSTY
+.Op Fl dknpAEGHMOLNRSTY
.Op Fl c , -script Ar script
.Op Fl h , -hostname Ar hostname
.Op Fl i , -classid Ar classid
.Op Fl l , -leasetime Ar seconds
.Op Fl m , -metric Ar metric
+.Op Fl o , -option Ar option
.Op Fl r , -request Ar address
.Op Fl t , -timeout Ar seconds
.Op Fl u , -userclass Ar class
.Pc .
Route metrics allow the addition of routes to the same destination across
different interfaces, the lower the metric the more it is preferred.
+.It Fl o , -option Ar option
+Request the DHCP
+.Ar option
+variable for use in
+.Pa @PREFIX@/etc/dhcpcd.sh .
.It Fl n , -renew
Notifies an existing
.Nm
Don't touch
.Pa /etc/ntpd.conf
or restart the ntp service.
+.It Fl O , -nooptions
+Don't request any options beyond what is needed to configure the interface.
.It Fl R , -nodns
Don't send DNS information to resolvconf or touch
.Pa /etc/resolv.conf .
{"leasetime", required_argument, NULL, 'l'},
{"metric", required_argument, NULL, 'm'},
{"renew", no_argument, NULL, 'n'},
+ {"option", required_argument, NULL, 'o'},
{"persistent", no_argument, NULL, 'p'},
{"inform", optional_argument, NULL, 's'},
{"request", optional_argument, NULL, 'r'},
{"noipv4ll", no_argument, NULL, 'L'},
{"nomtu", no_argument, NULL, 'M'},
{"nontp", no_argument, NULL, 'N'},
+ {"nooptions", no_argument, NULL, 'O'},
{"nodns", no_argument, NULL, 'R'},
{"msscr", no_argument, NULL, 'S'},
{"test", no_argument, NULL, 'T'},
static void
usage(void)
{
- printf("usage: "PACKAGE" [-adknpEGHMNRSTY] [-c script] [-h hostname] [-i classID]\n"
- " [-l leasetime] [-m metric] [-r ipaddress] [-s ipaddress]\n"
- " [-t timeout] [-u userclass] [-F none | ptr | both]\n"
+ printf("usage: "PACKAGE" [-adknpEGHMNORSTY] [-c script] [-h hostname] [-i classID]\n"
+ " [-l leasetime] [-m metric] [-o option] [-r ipaddress]\n"
+ " [-s ipaddress] [-t timeout] [-u userclass] [-F none | ptr | both]\n"
" [-I clientID] <interface>\n");
}
int sig = 0;
int retval = EXIT_FAILURE;
char *p;
+ int doopts = 1, dodns = 1, dohostname = 0, donis = 1, dontp = 1;
/* Close any un-needed fd's */
for (i = getdtablesize() - 1; i >= 3; --i)
strcmp(options->hostname, "localhost") == 0)
*options->hostname = '\0';
- setenv("PEERDNS", "yes", 1);
- setenv("PEERHOSTNAME", "no", 1);
- setenv("PEERNIS", "yes", 1);
- setenv("PEERNTP", "yes", 1);
-
/* Don't set any optional arguments here so we retain POSIX
* compatibility with getopt */
while ((opt = getopt_long(argc, argv, EXTRA_OPTS
- "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRSTY",
+ "c:dh:i:kl:m:no:pr:s:t:u:xAEF:GHI:LMNORSTY",
longopts, &option_index)) != -1)
{
switch (opt) {
case 'n':
sig = SIGALRM;
break;
+ case 'o':
+ if (make_reqmask(options, &optarg) != 0) {
+ logger(LOG_ERR, "unknown option `%s'", optarg);
+ goto abort;
+ }
case 'p':
options->options |= DHCPCD_PERSISTENT;
break;
options->options &= ~DHCPCD_GATEWAY;
break;
case 'H':
- setenv("PEERHOSTNAME", "yes", 1);
+ dohostname = 1;
break;
case 'I':
if (optarg) {
options->options &= ~DHCPCD_MTU;
break;
case 'N':
- setenv("PEERNTP", "no", 1);
+ dontp = 0;
+ break;
+ case 'O':
+ doopts = 0;
break;
case 'R':
- setenv("PEERDNS", "no", 1);
+ dodns = 0;
break;
case 'S':
options->domscsr++;
options->options |= DHCPCD_TEST | DHCPCD_PERSISTENT;
break;
case 'Y':
- setenv("PEERNIS", "no", 1);
+ donis = 0;
break;
case '?':
usage();
if (dohelp)
usage();
+ if (doopts) {
+ if (dodns) {
+ add_reqmask(options->reqmask, DHCP_DNSSERVER);
+ add_reqmask(options->reqmask, DHCP_DNSDOMAIN);
+ add_reqmask(options->reqmask, DHCP_DNSSEARCH);
+ }
+ if (dohostname)
+ add_reqmask(options->reqmask, DHCP_HOSTNAME);
+ if (donis) {
+ add_reqmask(options->reqmask, DHCP_NISSERVER);
+ add_reqmask(options->reqmask, DHCP_NISDOMAIN);
+ }
+ if (dontp)
+ add_reqmask(options->reqmask, DHCP_NTPSERVER);
+ }
+
#ifdef THERE_IS_NO_FORK
dhcpcd_argv = argv;
dhcpcd_argc = argc;
char classid[CLASS_ID_MAX_LEN];
char clientid[CLIENT_ID_MAX_LEN];
char userclass[USERCLASS_MAX_LEN];
+ uint8_t reqmask[256 / 8];
size_t userclass_len;
uint32_t leasetime;
time_t timeout;
}
make_nis_conf() {
- yesno "${PEERNIS}" || return 0
[ -z "${NISDOMAIN}" -a -z "${NISSERVER}" ] && return 0
local cf=/etc/yp.conf."${INTERFACE}" prefix= x= pidfile=
echo "# Generated by dhcpcd for interface ${INTERFACE}" > "${cf}"
restore_nis_conf()
{
- yesno "${PEERNIS}" || return 0
restore_conf /etc/yp.conf || return 0
pidfile="$(service_pidfile ypbind)"
if [ -s "${pidfile}" ]; then
make_ntp_conf()
{
- yesno "${PEERNTP}" || return 0
[ -z "${NTPSERVER}" ] && return 0
local cf=/etc/ntp.conf."${INTERFACE}" x=
echo "# Generated by dhcpcd for interface ${INTERFACE}" > "${cf}"
restore_ntp_conf()
{
- yesno "${PEERNTP}" || return 0
restore_conf /etc/ntp.conf || return 0
do_service ntp restart
}
make_resolv_conf()
{
- yesno "${PEERDNS}" || return 0
if [ -z "${DNSSERVER}" -a -z "${DNSDOMAIN}" -a -z "${DNSSEARCH}" ]; then
return 0
fi
restore_resolv_conf()
{
- yesno "${PEERDNS}" || return 0
if type resolvconf >/dev/null 2>&1; then
resolvconf -d "${INTERFACE}"
else
make_hostname()
{
- if yesno "${PEERHOSTNAME}" || need_hostname; then
+ if need_hostname; then
local name="${HOSTNAME}"
[ -z "${name}" ] && name="$(lookup_hostname)"
[ -n "${name}" ] && hostname "${name}"