Commit 79818c93 authored by Shawn Routhier's avatar Shawn Routhier
Browse files

[master] Add -df option to client code to help share DUIDs

Add the "-df <duid file>" option to the client code in order
to make it easier to share DUIDs between a v4 instance and
a v6 instance.  This option instructs the client to search
the duid file for a DUID if it didn't find one in the main
lease file.

In addition add the infrastructure for running ATF tests
for the client and write some ATF tests for this patch.
parent 63c8800c
......@@ -145,6 +145,13 @@ by Eric Young (eay@cryptsoft.com).
also be a change for currently running systems, so we have left it at 64.
[ISC-Bugs #DHCP-2]
- Add a run time option to the client "-df" to allow the administrator to
point to a second lease file the client can search for a DUID. This can
be used to allow a v4 and a v6 instance of the client to share a DUID.
The second file will only be searched if there isn't a DUID in the main
lease file and the DUID will be written out to the main lease file.
[ISC-Bugs #34886]
Changes since 4.3.0rc1
- None
......
# We want to build this directory first, before descending into tests subdir.
# The reason is that ideally the tests should link existing objects from this
# directory. That eliminates any discrepancies between tested code and
# production code. Sadly, we are not there yet.
SUBDIRS = . tests
dist_sysconf_DATA = dhclient.conf.example
sbin_PROGRAMS = dhclient
dhclient_SOURCES = clparse.c dhclient.c dhc6.c \
......
......@@ -130,6 +130,14 @@ am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(dhclient_SOURCES)
DIST_SOURCES = $(dhclient_SOURCES)
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
ctags-recursive dvi-recursive html-recursive info-recursive \
install-data-recursive install-dvi-recursive \
install-exec-recursive install-html-recursive \
install-info-recursive install-pdf-recursive \
install-ps-recursive install-recursive installcheck-recursive \
installdirs-recursive pdf-recursive ps-recursive \
tags-recursive uninstall-recursive
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
......@@ -167,6 +175,14 @@ man8dir = $(mandir)/man8
NROFF = nroff
MANS = $(man_MANS)
DATA = $(dist_sysconf_DATA)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
am__recursive_targets = \
$(RECURSIVE_TARGETS) \
$(RECURSIVE_CLEAN_TARGETS) \
$(am__extra_recursive_targets)
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
distdir
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
......@@ -186,7 +202,33 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = $(SUBDIRS)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
dir0=`pwd`; \
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
sed_rest='s,^[^/]*/*,,'; \
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
sed_butlast='s,/*[^/]*$$,,'; \
while test -n "$$dir1"; do \
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
if test "$$first" != "."; then \
if test "$$first" = ".."; then \
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
else \
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
if test "$$first2" = "$$first"; then \
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
else \
dir2="../$$dir2"; \
fi; \
dir0="$$dir0"/"$$first"; \
fi; \
fi; \
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
done; \
reldir="$$dir2"
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
......@@ -289,6 +331,12 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
# We want to build this directory first, before descending into tests subdir.
# The reason is that ideally the tests should link existing objects from this
# directory. That eliminates any discrepancies between tested code and
# production code. Sadly, we are not there yet.
SUBDIRS = . tests
dist_sysconf_DATA = dhclient.conf.example
dhclient_SOURCES = clparse.c dhclient.c dhc6.c \
scripts/bsdos scripts/freebsd scripts/linux scripts/macos \
......@@ -300,7 +348,7 @@ dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.a ../bind/lib/libirs.a \
man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
EXTRA_DIST = $(man_MANS)
all: all-am
all: all-recursive
.SUFFIXES:
.SUFFIXES: .c .o .obj
......@@ -512,14 +560,61 @@ uninstall-dist_sysconfDATA:
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(sysconfdir)'; $(am__uninstall_files_from_dir)
# This directory's subdirectories are mostly independent; you can cd
# into them and run 'make' without going through this Makefile.
# To change the values of 'make' variables: instead of editing Makefiles,
# (1) if the variable is set in 'config.status', edit 'config.status'
# (which will cause the Makefiles to be regenerated when you run 'make');
# (2) otherwise, pass the desired values on the 'make' command line.
$(am__recursive_targets):
@fail=; \
if $(am__make_keepgoing); then \
failcom='fail=yes'; \
else \
failcom='exit 1'; \
fi; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
case "$@" in \
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
*) list='$(SUBDIRS)' ;; \
esac; \
for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| eval $$failcom; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
tags: tags-recursive
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
include_option=--etags-include; \
empty_fix=.; \
else \
include_option=--include; \
empty_fix=; \
fi; \
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test ! -f $$subdir/TAGS || \
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
fi; \
done; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
......@@ -532,7 +627,7 @@ tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$$unique; \
fi; \
fi
ctags: ctags-am
ctags: ctags-recursive
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
......@@ -545,7 +640,7 @@ GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist: cscopelist-recursive
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
......@@ -594,22 +689,48 @@ distdir: $(DISTFILES)
|| exit 1; \
fi; \
done
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
$(am__make_dryrun) \
|| test -d "$(distdir)/$$subdir" \
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|| exit 1; \
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
$(am__relativize); \
new_distdir=$$reldir; \
dir1=$$subdir; dir2="$(top_distdir)"; \
$(am__relativize); \
new_top_distdir=$$reldir; \
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
($(am__cd) $$subdir && \
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$$new_top_distdir" \
distdir="$$new_distdir" \
am__remove_distdir=: \
am__skip_length_check=: \
am__skip_mode_fix=: \
distdir) \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
check: check-recursive
all-am: Makefile $(PROGRAMS) $(MANS) $(DATA)
installdirs:
installdirs: installdirs-recursive
installdirs-am:
for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(sysconfdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
installcheck: installcheck-recursive
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
......@@ -631,70 +752,70 @@ distclean-generic:
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean: clean-recursive
clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am
distclean: distclean-am
distclean: distclean-recursive
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi: dvi-recursive
dvi-am:
html: html-am
html: html-recursive
html-am:
info: info-am
info: info-recursive
info-am:
install-data-am: install-man
install-dvi: install-dvi-am
install-dvi: install-dvi-recursive
install-dvi-am:
install-exec-am: install-dist_sysconfDATA install-sbinPROGRAMS
install-html: install-html-am
install-html: install-html-recursive
install-html-am:
install-info: install-info-am
install-info: install-info-recursive
install-info-am:
install-man: install-man5 install-man8
install-pdf: install-pdf-am
install-pdf: install-pdf-recursive
install-pdf-am:
install-ps: install-ps-am
install-ps: install-ps-recursive
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
maintainer-clean: maintainer-clean-recursive
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf: pdf-recursive
pdf-am:
ps: ps-am
ps: ps-recursive
ps-am:
......@@ -703,23 +824,23 @@ uninstall-am: uninstall-dist_sysconfDATA uninstall-man \
uninstall-man: uninstall-man5 uninstall-man8
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \
distclean-compile distclean-generic distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dist_sysconfDATA \
install-dvi install-dvi-am install-exec install-exec-am \
install-html install-html-am install-info install-info-am \
install-man install-man5 install-man8 install-pdf \
install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-dist_sysconfDATA \
uninstall-man uninstall-man5 uninstall-man8 \
uninstall-sbinPROGRAMS
.MAKE: $(am__recursive_targets) install-am install-strip
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
check-am clean clean-generic clean-sbinPROGRAMS cscopelist-am \
ctags ctags-am distclean distclean-compile distclean-generic \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am \
install-dist_sysconfDATA install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-man5 \
install-man8 install-pdf install-pdf-am install-ps \
install-ps-am install-sbinPROGRAMS install-strip installcheck \
installcheck-am installdirs installdirs-am maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am uninstall-dist_sysconfDATA uninstall-man \
uninstall-man5 uninstall-man8 uninstall-sbinPROGRAMS
dhclient.o: dhclient.c
......
......@@ -244,6 +244,45 @@ int read_client_conf_file (const char *name, struct interface_info *ip,
}
/* lease-file :== client-lease-statements END_OF_FILE
client-lease-statements :== <nil>
| client-lease-statements LEASE client-lease-statement
* This routine looks through a lease file and only tries to parse
* the duid statements.
*/
void read_client_duid ()
{
int file;
isc_result_t status;
struct parse *cfile;
const char *val;
int token;
/* 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_duid, O_RDONLY)) < 0)
return;
cfile = NULL;
status = new_parse(&cfile, file, NULL, 0, path_dhclient_duid, 0);
if (status != ISC_R_SUCCESS || cfile == NULL)
return;
while ((token = next_token(&val, NULL, cfile)) != END_OF_FILE) {
/*
* All we care about is DUIDs - if we get anything else
* just toss it and continue looking for DUIDs until we
* run out of file.
*/
if (token == DEFAULT_DUID) {
parse_client_default_duid(cfile);
}
}
end_parse(&cfile);
}
/* lease-file :== client-lease-statements END_OF_FILE
client-lease-statements :== <nil>
| client-lease-statements LEASE client-lease-statement */
......
......@@ -73,6 +73,10 @@ dhclient - Dynamic Host Configuration Protocol Client
.B -d
]
[
.B -df
.I duid-lease-file
]
[
.B -e
.I VAR=value
]
......@@ -391,6 +395,16 @@ Path to the client configuration file. If unspecified, the default
.B ETCDIR/dhclient.conf
is used. See \fBdhclient.conf(5)\fR for a description of this file.
.TP
.BI \-df \ duid-lease-file
Path to a secondary lease file. If the primary lease file doesn't contain
a DUID this file will be searched. The DUID read from the secondary will
be written to the primary. This option can be used to allow an IPv4 instance
of the client to share a DUID with an IPv6 instance. After starting one of
the instances the second can be started with this option pointing to the
lease file of the first instance. There is no default. If no file is
specified no search is made for a DUID should one not be found in the main
lease file.
.TP
.BI \-lf \ lease-file
Path to the lease database file. If unspecified, the default
.B DBDIR/dhclient.leases
......
......@@ -47,6 +47,7 @@ const char *path_dhclient_db = NULL;
const char *path_dhclient_pid = NULL;
static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT;
char *path_dhclient_script = path_dhclient_script_array;
const char *path_dhclient_duid = NULL;
/* False (default) => we write and use a pid file */
isc_boolean_t no_pid_file = ISC_FALSE;
......@@ -100,6 +101,7 @@ static int check_domain_name_list(const char *ptr, size_t len, int dots);
static int check_option_values(struct universe *universe, unsigned int opt,
const char *ptr, size_t len);
#ifndef UNIT_TEST
int
main(int argc, char **argv) {
int fd;
......@@ -210,6 +212,10 @@ main(int argc, char **argv) {
usage();
path_dhclient_conf = argv[i];
no_dhclient_conf = 1;
} else if (!strcmp(argv[i], "-df")) {
if (++i == argc)
usage();
path_dhclient_duid = argv[i];
} else if (!strcmp(argv[i], "-lf")) {
if (++i == argc)
usage();
......@@ -504,6 +510,11 @@ main(int argc, char **argv) {
/* Parse the lease database. */
read_client_leases();
/* If desired parse the secondary lease database for a DUID */
if ((default_duid.len == 0) && (path_dhclient_duid != NULL)) {
read_client_duid();
}
/* Rewrite the lease database... */
rewrite_client_leases();
......@@ -723,6 +734,7 @@ main(int argc, char **argv) {
/* In fact dispatch() never returns. */
return 0;
}
#endif /* !UNIT_TEST */
static void usage()
{
......@@ -738,8 +750,8 @@ static void usage()
#else /* DHCPv6 */
"[-I1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
#endif /* DHCPv6 */
" [-s server-addr] [-cf config-file] "
"[-lf lease-file]\n"
" [-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]");
}
......@@ -763,6 +775,11 @@ void run_stateless(int exit_mode)
/* Parse the lease database. */
read_client_leases();
/* If desired parse the secondary lease database for a DUID */
if ((default_duid.len == 0) && (path_dhclient_duid != NULL)) {
read_client_duid();
}
/* Establish a default DUID. */
if (default_duid.len == 0) {
if (default_duid.buffer != NULL)
......@@ -2884,6 +2901,7 @@ form_duid(struct data_string *duid, const char *file, int line)
{
struct interface_info *ip;
int len;
char *str;
/* For now, just use the first interface on the list. */
ip = interfaces;
......@@ -2926,6 +2944,14 @@ form_duid(struct data_string *duid, const char *file, int line)
memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1,
ip->hw_address.hlen - 1);
}
str = quotify_buf(duid->data, duid->len, MDL);
if (str == NULL)
log_info("Created duid.");
else {
log_info("Created duid %s.", str);
dfree(str, MDL);
}
}
/* Write the default DUID to the lease store. */
......
Content-Type: application/X-atf-atffile; version="1"
prop: test-suite = dhcp4
tp-glob: *_unittests
SUBDIRS = .
AM_CPPFLAGS = $(ATF_CFLAGS) -DUNIT_TEST -I$(top_srcdir)/includes
AM_CPPFLAGS += -I$(top_srcdir)/bind/include -I$(top_srcdir)
AM_CPPFLAGS += -DLOCALSTATEDIR='"."'
AM_CPPFLAGS += -DCLIENT_PATH='"."'
EXTRA_DIST = Atffile duid0_test.txt duid1_test.txt duid2_test.txt duid3_test.txt
# for autotools debugging only
info:
@echo "ATF_CFLAGS=$(ATF_CFLAGS)"
@echo "ATF_LDFLAGS=$(ATF_LDFLAGS)"
@echo "ATF_LIBS=$(ATF_LIBS)"
DHCPSRC = ../clparse.c ../dhc6.c ../dhclient.c
DHCPLIBS = $(top_builddir)/common/libdhcp.a $(top_builddir)/omapip/libomapi.a \
$(top_builddir)/dhcpctl/libdhcpctl.a $(top_builddir)/bind/lib/libirs.a \
$(top_builddir)/bind/lib/libdns.a $(top_builddir)/bind/lib/libisccfg.a \
$(top_builddir)/bind/lib/libisc.a
ATF_TESTS =
TESTS =
if HAVE_ATF
check: $(ATF_TESTS)
atf-run | atf-report
ATF_TESTS += duid_unittests
duid_unittests_SOURCES = $(DHCPSRC)
duid_unittests_SOURCES += duid_unittest.c
duid_unittests_LDADD = $(ATF_LDFLAGS)
duid_unittests_LDADD += $(DHCPLIBS)
endif
check_PROGRAMS = $(ATF_TESTS) $(TESTS)
This diff is collapsed.
lease {
interface "em1";
fixed-address 172.16.132.152;
option subnet-mask 255.255.255.0;
option dhcp-lease-time 60;
option routers 17.132.16.200;
option dhcp-message-type 5;
option dhcp-server-identifier 172.16.132.200;
option dhcp-renewal-time 30;
option dhcp-rebinding-time 45;
option domain-name "example.org";
renew 2 2014/05/13 23:11:53;
rebind 2 2014/05/13 23:11:53;
expire 2 2014/05/13 23:11:53;
}
default-duid "\000\001";
lease6 {
interface "em1";
ia-na 56:32:02:02 {
starts 1399436400;
renew 3;
rebind 15;
iaaddr 2000::37a {
starts 1399436400;
preferred-life 18;
max-life 30;
}
}
option dhcp6.client-id 0:1:0:1:1a:1:2d:7c:0:50:56:32:2:2;
option dhcp6.server-id 0:1:0:1:19:fd:aa:20:0:50:56:2f:de:8a;
option dhcp6.name-servers 2000::2;
}
default-duid "\000\001\000\001\001\002\003\004\005\006\007\010\011\012";
default-duid "\000\003\000\001\005\006\007\010\011\012";
lease {
interface "em1";
fixed-address 172.16.132.152;
option subnet-mask 255.255.255.0;
option dhcp-lease-time 60;