+#etc/dhclient.conf
etc/dhcpd.conf
-#sbin/dhclient
-#sbin/dhclient-script
#usr/bin/omshell
-#usr/include/dhcpctl.h
+#usr/include/dhcpctl
+#usr/include/dhcpctl/dhcpctl.h
#usr/include/isc-dhcp
-#usr/include/isc-dhcp/boolean.h
#usr/include/isc-dhcp/dst.h
-#usr/include/isc-dhcp/int.h
-#usr/include/isc-dhcp/lang.h
-#usr/include/isc-dhcp/list.h
-#usr/include/isc-dhcp/result.h
-#usr/include/isc-dhcp/types.h
#usr/include/omapip
#usr/include/omapip/alloc.h
#usr/include/omapip/buffer.h
+#usr/include/omapip/convert.h
+#usr/include/omapip/hash.h
+#usr/include/omapip/isclib.h
#usr/include/omapip/omapip.h
+#usr/include/omapip/omapip_p.h
+#usr/include/omapip/result.h
+#usr/include/omapip/trace.h
#usr/lib/libdhcpctl.a
+#usr/lib/libdst.a
#usr/lib/libomapi.a
-#usr/man/man1/omshell.1
-#usr/man/man3/dhcpctl.3
-#usr/man/man3/omapi.3
-#usr/man/man3/omshell.3
-#usr/man/man5/dhclient.conf.5
-#usr/man/man5/dhclient.leases.5
-#usr/man/man5/dhcp-eval.5
-#usr/man/man5/dhcp-options.5
-#usr/man/man5/dhcpd.conf.5
-#usr/man/man5/dhcpd.leases.5
-#usr/man/man8/dhclient-script.8
-#usr/man/man8/dhclient.8
-#usr/man/man8/dhcpd.8
-#usr/man/man8/dhcrelay.8
+#usr/sbin/dhclient
usr/sbin/dhcpd
#usr/sbin/dhcrelay
+#usr/share/man/man1/omshell.1
+#usr/share/man/man3/dhcpctl.3
+#usr/share/man/man3/omapi.3
+#usr/share/man/man5/dhclient.conf.5
+#usr/share/man/man5/dhclient.leases.5
+#usr/share/man/man5/dhcp-eval.5
+#usr/share/man/man5/dhcp-options.5
+#usr/share/man/man5/dhcpd.conf.5
+#usr/share/man/man5/dhcpd.leases.5
+#usr/share/man/man8/dhclient-script.8
+#usr/share/man/man8/dhclient.8
+#usr/share/man/man8/dhcpd.8
+#usr/share/man/man8/dhcrelay.8
#var/state
#var/state/dhcp
var/state/dhcp/dhcpd.leases
#usr/bin/rlogin
#usr/bin/rsh
#usr/bin/talk
-#usr/bin/telnet
#usr/bin/tftp
usr/bin/whois
#usr/sbin/ftpd
#usr/sbin/rlogind
#usr/sbin/rshd
#usr/sbin/talkd
-#usr/sbin/telnetd
#usr/sbin/tftpd
#usr/sbin/uucpd
#usr/share/info/inetutils.info
--- /dev/null
+usr/bin/telnet
+#usr/man/man1/telnet.1
+#usr/man/man5/issue.net.5
+#usr/sbin/in.telnetd
if ($sovpnsettings{CLIENT2CLIENT} eq 'on') {
print CONF "client-to-client\n";
}
- if ($sovpnsettings{'DPROTOCOL'} eq 'udp') {
- if ($sovpnsettings{MSSFIX} eq 'on') {
- print CONF "mssfix\n";
- }
- if ($sovpnsettings{'FRAGMENT'} eq '' || $sovpnsettings{'FRAGMENT'} eq 0) {
- $sovpnsettings{'FRAGMENT'} = '1300';
- }
- print CONF "fragment $sovpnsettings{'FRAGMENT'}\n";
+ if ($sovpnsettings{MSSFIX} eq 'on') {
+ print CONF "mssfix\n";
+ }
+ if ($sovpnsettings{FRAGMENT} ne '' && $sovpnsettings{'DPROTOCOL'} ne 'tcp') {
+ print CONF "fragment $sovpnsettings{'FRAGMENT'}\n";
}
if ($sovpnsettings{KEEPALIVE_1} > 0 && $sovpnsettings{KEEPALIVE_2} > 0) {
print CONF "keepalive $sovpnsettings{'KEEPALIVE_1'} $sovpnsettings{'KEEPALIVE_2'}\n";
}
}
if ($cgiparams{'MSSFIX'} ne 'on') {
- $vpnsettings{'MSSFIX'} = 'off';
+ delete $vpnsettings{'MSSFIX'};
} else {
$vpnsettings{'MSSFIX'} = $cgiparams{'MSSFIX'};
}
if ($cgiparams{'LOG_VERB'} eq '') {
$cgiparams{'LOG_VERB'} = '3';
}
- if ($cgiparams{'MSSFIX'} eq '') {
- $cgiparams{'MSSFIX'} = 'on';
- }
- if ($cgiparams{'FRAGMENT'} eq '') {
- $cgiparams{'FRAGMENT'} = '1300';
- }
$checked{'CLIENT2CLIENT'}{'off'} = '';
$checked{'CLIENT2CLIENT'}{'on'} = '';
$checked{'CLIENT2CLIENT'}{$cgiparams{'CLIENT2CLIENT'}} = 'CHECKED';
include Config
-VER = 3.1-ESV-R3
+VER = 4.2.2
THISAPP = dhcp-$(VER)
DL_FILE = $(THISAPP).tar.gz
$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
-$(DL_FILE)_MD5 = af3d8db60f62664f1d5538b81e406459
+$(DL_FILE)_MD5 = bb0f0434cd796f76aa7cead391d71f31
install : $(TARGET)
$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
@$(PREBUILD)
@rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
+
cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-3.1_linux3.patch
- cd $(DIR_APP) && ./configure
+
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-remove-bind.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-errwarn-message.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-options.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-release-by-ifup.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-dhclient-decline-backoff.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-unicast-bootp.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-dhclient-usage.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-default-requested-options.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-xen-checksum.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-manpages.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-paths.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-CLOEXEC.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-inherit-leases.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-garbage-chars.patch
+ # ???
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-missing-ipv6-not-fatal.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-add_timeout_when_NULL.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-64_bit_lease_parse.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-capability.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-logpid.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-UseMulticast.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-sendDecline.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-retransmission.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-rfc3442-classless-static-routes.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-honor-expired.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-noprefixavail.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-sharedlib.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.0-PPP.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-lpf-ib.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-improved-xid.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.2-gpxe-cid.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/dhcp-4.2.1-invalid-dhclient-conf.patch
+
+ # Remove bundled BIND stuff.
+ # (requires newer autoconf)
+ #rm -rfv $(DIR_APP)/bind/bind.tar.gz
+ #cd $(DIR_APP) && autoreconf --verbose --force --install
+
+ cd $(DIR_APP) && \
+ ./configure \
+ --prefix=/usr \
+ --sysconfdir=/etc \
+ --with-srv-lease-file=/var/state/dhcp/dhcpd.leases \
+ --disable-static \
+ --enable-paranoia \
+ --enable-early-chroot \
+ --disable-dhcpv6
+
cd $(DIR_APP) && make $(MAKETUNING)
- cd $(DIR_APP) && make LIBDIR=/usr/lib INCDIR=/usr/include install
+ cd $(DIR_APP) && make install
+
+ mkdir -pv /var/state/dhcp
touch /var/state/dhcp/dhcpd.leases
+
ln -sf $(CONFIG_ROOT)/dhcp/dhcpd.conf /etc/dhcpd.conf
@rm -rf $(DIR_APP)
@$(POSTBUILD)
include Config
-VER = 2.1.5
+VER = 2.1.6
THISAPP = fireinfo-v$(VER)
DL_FILE = $(THISAPP).tar.gz
$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
-$(DL_FILE)_MD5 = 7f5350212b6aff44cb361fcabdf991e0
+$(DL_FILE)_MD5 = ff8eb520af49c0bf00722aac167070cd
install : $(TARGET)
include Config
-VER = 3.1
+VER = 3.4
THISAPP = fping-$(VER)
DL_FILE = $(THISAPP).tar.gz
DIR_APP = $(DIR_SRC)/$(THISAPP)
TARGET = $(DIR_INFO)/$(THISAPP)
PROG = fping
-PAK_VER = 1
+PAK_VER = 2
DEPS = ""
$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
-$(DL_FILE)_MD5 = a2bbf3316da8c7b47a1a0ffe959d5d9e
+$(DL_FILE)_MD5 = a4bc97804e630dbf26dfac8f28c78091
install : $(TARGET)
cd $(DIR_APP) && ./configure --prefix=/usr --libexecdir=/usr/sbin \
--sysconfdir=/etc --localstatedir=/var \
--mandir=/usr/share/man --infodir=/usr/share/info \
- --disable-logger --disable-syslogd
+ --disable-logger --disable-syslogd --disable-telnet --disable-telnetd
cd $(DIR_APP) && make $(MAKETUNING)
cd $(DIR_APP) && make install
mv -v /usr/bin/ping /bin
DIR_APP = $(DIR_SRC)/$(THISAPP)
TARGET = $(DIR_INFO)/$(THISAPP)
PROG = minidlna
-PAK_VER = 1
+PAK_VER = 2
-DEPS = "ffmpeg flac libexif libid3tag libogg"
+DEPS = "ffmpeg flac libexif libid3tag libogg sqlite"
###############################################################################
# Top-level Rules
--- /dev/null
+###############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2007 Michael Tremer & Christian Schmidt #
+# #
+# 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 3 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 <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+###############################################################################
+# Definitions
+###############################################################################
+
+include Config
+
+VER = 0.17
+THISAPP = netkit-telnet-$(VER)
+DL_FILE = $(THISAPP).tar.gz
+DL_FROM = $(URL_IPFIRE)
+DIR_APP = $(DIR_SRC)/$(THISAPP)
+TARGET = $(DIR_INFO)/$(THISAPP)
+PROG = telnet
+PAK_VER = 1
+
+DEPS = ""
+
+###############################################################################
+# Top-level Rules
+###############################################################################
+
+objects = $(DL_FILE) \
+ telnet-client.tar.gz
+
+$(DL_FILE) = $(DL_FROM)/$(DL_FILE)
+telnet-client.tar.gz = $(DL_FROM)/telnet-client.tar.gz
+
+$(DL_FILE)_MD5 = d6beabaaf53fe6e382c42ce3faa05a36
+telnet-client.tar.gz_MD5 = d74983062470c5a3e7ae14f34c489e00
+
+install : $(TARGET)
+
+check : $(patsubst %,$(DIR_CHK)/%,$(objects))
+
+download :$(patsubst %,$(DIR_DL)/%,$(objects))
+
+md5 : $(subst %,%_MD5,$(objects))
+
+dist:
+ @$(PAK)
+
+###############################################################################
+# Downloading, checking, md5sum
+###############################################################################
+
+$(patsubst %,$(DIR_CHK)/%,$(objects)) :
+ @$(CHECK)
+
+$(patsubst %,$(DIR_DL)/%,$(objects)) :
+ @$(LOAD)
+
+$(subst %,%_MD5,$(objects)) :
+ @$(MD5)
+
+###############################################################################
+# Installation Details
+###############################################################################
+
+$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
+ @$(PREBUILD)
+ @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE)
+ cd ${DIR_APP} && mv telnet telnet-netkit
+ cd ${DIR_APP} && tar zxf $(DIR_DL)/telnet-client.tar.gz
+ cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/telnet-client-cvs.patch0
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-0.17-env.patch
+ cd $(DIR_APP) && patch -Np0 -i $(DIR_SRC)/src/patches/telnet-0.17-pek.patch0
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-0.17-issue.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-0.17-sa-01-49.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-0.17-8bit.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-0.17-argv.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-0.17-conf.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-0.17-cleanup_race.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-0.17-CAN-2005-468_469.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-gethostbyname.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/netkit-telnet-0.17-ipv6.diff
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/netkit-telnet-0.17-nodns.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/telnet-0.17-errno_test_sys_bsd.patch
+ cd $(DIR_APP) && patch -Np1 -i $(DIR_SRC)/src/patches/netkit-telnet-0.17-reallynodns.patch
+ cd $(DIR_APP) && ./configure --prefix=/usr
+ cd $(DIR_APP) && make
+ cd $(DIR_APP) && make install
+ rm -f /usr/sbin/telnetd
+ rm -f /usr/man/man8/in.telnetd.8
+ rm -f /usr/man/man8/telnetd.8
+ @rm -rf $(DIR_APP)
+ @$(POSTBUILD)
export LOGFILE
ipfiremake configroot
ipfiremake backup
+ ipfiremake bind
ipfiremake dhcp
ipfiremake dhcpcd
ipfiremake libusb
ipfiremake apache2 PASS=C
ipfiremake arping
ipfiremake beep
- ipfiremake bind
ipfiremake dvdrtools
ipfiremake dnsmasq
ipfiremake dosfstools
ipfiremake minidlna
ipfiremake acpid
ipfiremake fping
+ ipfiremake telnet
echo Build on $HOSTNAME > $BASEDIR/build/var/ipfire/firebuild
cat /proc/version >> $BASEDIR/build/var/ipfire/firebuild
echo >> $BASEDIR/build/var/ipfire/firebuild
# Skip immediately if no configuration file has been found.
[ -e "${CONFIG_FILE}" ] || exit 0
-eval $(readhash ${CONFIG_FILE})
+eval $(/usr/local/bin/readhash ${CONFIG_FILE})
# This is start or stop.
action=${1}
case "${action}" in
start)
+ # If no parent device has been configured, we assume
+ # that this interface is not set up for VLANs and
+ # silently go on.
+ [ -z "${PARENT_DEV}" ] && continue
+
# Check if the interface does already exists.
# If so, we skip creating it.
if [ -d "/sys/class/net/${interface}" ]; then
- echo "Interface ${interface} already exists."
+ echo "Interface ${interface} already exists." >&2
continue
fi
# Check if the parent interface exists.
- if [ -z "${PARENT_DEV}" ] || [ ! -d "/sys/class/net/${PARENT_DEV}" ]; then
- echo "${interface}: Parent device is not set or does not exist: ${PARENT_DEV}"
+ if [ ! -d "/sys/class/net/${PARENT_DEV}" ]; then
+ echo "${interface}: Parent device is not set or does not exist: ${PARENT_DEV}" >&2
continue
fi
if [ -z "${VLAN_ID}" ]; then
- echo "${interface}: You did not set the VLAN ID."
+ echo "${interface}: You did not set the VLAN ID." >&2
continue
fi
--- /dev/null
+diff -up dhcp-4.2.0-P1/client/dhc6.c.PPP dhcp-4.2.0-P1/client/dhc6.c
+--- dhcp-4.2.0-P1/client/dhc6.c.PPP 2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/client/dhc6.c 2010-11-09 15:54:12.000000000 +0100
+@@ -129,7 +129,7 @@ extern int stateless;
+ * 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;
+@@ -141,6 +141,15 @@ form_duid(struct data_string *duid, cons
+ 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);
+@@ -176,6 +185,8 @@ form_duid(struct data_string *duid, cons
+ memcpy(duid->buffer->data + 4, ip->hw_address.hbuf + 1,
+ ip->hw_address.hlen - 1);
+ }
++
++ return ISC_R_SUCCESS;
+ }
+
+ /*
+@@ -5289,7 +5300,8 @@ make_client6_options(struct client_state
+ */
+ 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 -up dhcp-4.2.0-P1/client/dhclient.c.PPP dhcp-4.2.0-P1/client/dhclient.c
+--- dhcp-4.2.0-P1/client/dhclient.c.PPP 2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/client/dhclient.c 2010-11-09 15:37:26.000000000 +0100
+@@ -911,8 +911,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);
+ }
+
+ for (ip = interfaces ; ip != NULL ; ip = ip->next) {
+diff -up dhcp-4.2.0-P1/common/bpf.c.PPP dhcp-4.2.0-P1/common/bpf.c
+--- dhcp-4.2.0-P1/common/bpf.c.PPP 2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/common/bpf.c 2010-11-09 15:42:42.000000000 +0100
+@@ -599,6 +599,22 @@ get_hw_addr(const char *name, struct har
+ 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 -up dhcp-4.2.0-P1/common/lpf.c.PPP dhcp-4.2.0-P1/common/lpf.c
+--- dhcp-4.2.0-P1/common/lpf.c.PPP 2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/common/lpf.c 2010-11-09 15:45:40.000000000 +0100
+@@ -502,6 +502,22 @@ get_hw_addr(const char *name, struct har
+ hw->hbuf[0] = HTYPE_FDDI;
+ memcpy(&hw->hbuf[1], sa->sa_data, 16);
+ 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 -up dhcp-4.2.0-P1/includes/dhcpd.h.PPP dhcp-4.2.0-P1/includes/dhcpd.h
+--- dhcp-4.2.0-P1/includes/dhcpd.h.PPP 2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/includes/dhcpd.h 2010-11-09 15:46:58.000000000 +0100
+@@ -2733,7 +2733,7 @@ void dhcpv4_client_assignments(void);
+ void dhcpv6_client_assignments(void);
+
+ /* dhc6.c */
+-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 dhc6_lease_destroy(struct dhc6_lease **src, const char *file, int line);
+ void start_init6(struct client_state *client);
+ void start_info_request6(struct client_state *client);
+diff -up dhcp-4.2.0-P1/includes/dhcp.h.PPP dhcp-4.2.0-P1/includes/dhcp.h
+--- dhcp-4.2.0-P1/includes/dhcp.h.PPP 2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/includes/dhcp.h 2010-11-09 15:48:53.000000000 +0100
+@@ -80,6 +80,8 @@ struct dhcp_packet {
+ #define HTYPE_IEEE802 6 /* IEEE 802.2 Token Ring... */
+ #define HTYPE_FDDI 8 /* FDDI... */
+
++#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 -up dhcp-4.2.0-P1/server/dhcpv6.c.PPP dhcp-4.2.0-P1/server/dhcpv6.c
+--- dhcp-4.2.0-P1/server/dhcpv6.c.PPP 2010-11-05 10:47:37.000000000 +0100
++++ dhcp-4.2.0-P1/server/dhcpv6.c 2010-11-09 15:50:17.000000000 +0100
+@@ -300,6 +300,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;
--- /dev/null
+diff -up dhcp-4.2.0/server/dhcpv6.c.UseMulticast dhcp-4.2.0/server/dhcpv6.c
+--- dhcp-4.2.0/server/dhcpv6.c.UseMulticast 2010-06-01 19:30:00.000000000 +0200
++++ dhcp-4.2.0/server/dhcpv6.c 2010-07-21 16:17:30.000000000 +0200
+@@ -346,6 +346,48 @@ generate_new_server_duid(void) {
+ }
+
+ /*
++ * Is the D6O_UNICAST option defined in dhcpd.conf ?
++ */
++static isc_boolean_t unicast_option_defined;
++
++/*
++ * Did we already search dhcpd.conf for D6O_UNICAST option ?
++ * We need to store it here to not parse dhcpd.conf repeatedly.
++ */
++static isc_boolean_t unicast_option_parsed = ISC_FALSE;
++
++
++/*
++ * Is the D6O_UNICAST option defined in dhcpd.conf ?
++ */
++isc_boolean_t
++is_unicast_option_defined(void) {
++ struct option_state *opt_state;
++ struct option_cache *oc;
++
++ /*
++ * If we are looking for the unicast option for the first time
++ */
++ if (unicast_option_parsed == ISC_FALSE) {
++ unicast_option_parsed = ISC_TRUE;
++ opt_state = NULL;
++ if (!option_state_allocate(&opt_state, MDL)) {
++ log_fatal("No memory for option state.");
++ }
++
++ execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
++ opt_state, &global_scope, root_group, NULL);
++
++ oc = lookup_option(&dhcpv6_universe, opt_state, D6O_UNICAST);
++ unicast_option_defined = (oc != NULL);
++
++ option_state_dereference(&opt_state, MDL);
++ }
++
++ return (unicast_option_defined);
++}
++
++/*
+ * Get the client identifier from the packet.
+ */
+ isc_result_t
+@@ -1405,6 +1447,56 @@ lease_to_client(struct data_string *repl
+ reply.shared->group);
+ }
+
++ /* reject unicast message, unless we set unicast option */
++ if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined())
++ /*
++ * RFC3315 section 18.2.1 (Request):
++ *
++ * When the server receives a Request message via unicast from a client
++ * to which the server has not sent a unicast option, the server
++ * discards the Request message and responds with a Reply message
++ * containing a Status Code option with the value UseMulticast, a Server
++ * Identifier option containing the server's DUID, the Client Identifier
++ * option from the client message, and no other options.
++ *
++ * Section 18.2.3 (Renew):
++ *
++ * When the server receives a Renew message via unicast from a client to
++ * which the server has not sent a unicast option, the server discards
++ * the Renew message and responds with a Reply message containing a
++ * Status Code option with the value UseMulticast, a Server Identifier
++ * option containing the server's DUID, the Client Identifier option
++ * from the client message, and no other options.
++ */
++ {
++ /* Set the UseMulticast status code. */
++ if (!set_status_code(STATUS_UseMulticast,
++ "Unicast not allowed by server.",
++ reply.opt_state)) {
++ log_error("lease_to_client: Unable to set "
++ "UseMulticast status code.");
++ goto exit;
++ }
++
++ /* Rewind the cursor to the start. */
++ reply.cursor = REPLY_OPTIONS_INDEX;
++
++ /*
++ * Produce an reply that includes only:
++ *
++ * Status code.
++ * Server DUID.
++ * Client DUID.
++ */
++ reply.cursor += store_options6((char *)reply.buf.data +
++ reply.cursor,
++ sizeof(reply.buf) -
++ reply.cursor,
++ reply.opt_state, reply.packet,
++ required_opts_NAA,
++ NULL);
++ } else if (no_resources_avail && (reply.ia_count != 0) &&
++ (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
+ /*
+ * RFC3315 section 17.2.2 (Solicit):
+ *
+@@ -1429,8 +1521,6 @@ lease_to_client(struct data_string *repl
+ * the server.
+ * Sends a Renew/Rebind if the IA is not in the Reply message.
+ */
+- if (no_resources_avail && (reply.ia_count != 0) &&
+- (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
+ {
+ /* Set the NoAddrsAvail status code. */
+ if (!set_status_code(STATUS_NoAddrsAvail,
+@@ -4128,7 +4218,6 @@ dhcpv6_solicit(struct data_string *reply
+ * Very similar to Solicit handling, except the server DUID is required.
+ */
+
+-/* TODO: reject unicast messages, unless we set unicast option */
+ static void
+ dhcpv6_request(struct data_string *reply_ret, struct packet *packet) {
+ struct data_string client_id;
+@@ -4443,7 +4532,6 @@ exit:
+ * except for the error code of when addresses don't match.
+ */
+
+-/* TODO: reject unicast messages, unless we set unicast option */
+ static void
+ dhcpv6_renew(struct data_string *reply, struct packet *packet) {
+ struct data_string client_id;
+@@ -4688,18 +4776,60 @@ iterate_over_ia_na(struct data_string *r
+ goto exit;
+ }
+
+- snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
+- if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
+- goto exit;
+- }
++ /* reject unicast message, unless we set unicast option */
++ if ((packet->unicast == ISC_TRUE) && !is_unicast_option_defined()) {
++ /*
++ * RFC3315 section 18.2.6 (Release):
++ *
++ * When the server receives a Release message via unicast from a client
++ * to which the server has not sent a unicast option, the server
++ * discards the Release message and responds with a Reply message
++ * containing a Status Code option with value UseMulticast, a Server
++ * Identifier option containing the server's DUID, the Client Identifier
++ * option from the client message, and no other options.
++ *
++ * Section 18.2.7 (Decline):
++ *
++ * When the server receives a Decline message via unicast from a client
++ * to which the server has not sent a unicast option, the server
++ * discards the Decline message and responds with a Reply message
++ * containing a Status Code option with the value UseMulticast, a Server
++ * Identifier option containing the server's DUID, the Client Identifier
++ * option from the client message, and no other options.
++ */
++ snprintf(status_msg, sizeof(status_msg),
++ "%s received unicast.", packet_type);
++ if (!set_status_code(STATUS_UseMulticast, status_msg, opt_state)) {
++ goto exit;
++ }
+
+- /*
+- * Add our options that are not associated with any IA_NA or IA_TA.
+- */
+- reply_ofs += store_options6(reply_data+reply_ofs,
+- sizeof(reply_data)-reply_ofs,
++ /*
++ * Produce an reply that includes only:
++ *
++ * Status code.
++ * Server DUID.
++ * Client DUID.
++ */
++ reply_ofs += store_options6(reply_data+reply_ofs,
++ sizeof(reply_data)-reply_ofs,
+ opt_state, packet,
+- required_opts, NULL);
++ required_opts_NAA, NULL);
++
++ goto return_reply;
++ } else {
++ snprintf(status_msg, sizeof(status_msg), "%s received.", packet_type);
++ if (!set_status_code(STATUS_Success, status_msg, opt_state)) {
++ goto exit;
++ }
++
++ /*
++ * Add our options that are not associated with any IA_NA or IA_TA.
++ */
++ reply_ofs += store_options6(reply_data+reply_ofs,
++ sizeof(reply_data)-reply_ofs,
++ opt_state, packet,
++ required_opts, NULL);
++ }
+
+ /*
+ * Loop through the IA_NA reported by the client, and deal with
+@@ -4838,6 +4968,7 @@ iterate_over_ia_na(struct data_string *r
+ /*
+ * Return our reply to the caller.
+ */
++return_reply:
+ reply_ret->len = reply_ofs;
+ reply_ret->buffer = NULL;
+ if (!buffer_allocate(&reply_ret->buffer, reply_ofs, MDL)) {
+@@ -4883,7 +5014,6 @@ exit:
+ * we still need to be aware of this possibility.
+ */
+
+-/* TODO: reject unicast messages, unless we set unicast option */
+ /* TODO: IA_TA */
+ static void
+ dhcpv6_decline(struct data_string *reply, struct packet *packet) {
+@@ -5355,7 +5485,6 @@ exit:
+ * Release means a client is done with the leases.
+ */
+
+-/* TODO: reject unicast messages, unless we set unicast option */
+ static void
+ dhcpv6_release(struct data_string *reply, struct packet *packet) {
+ struct data_string client_id;
--- /dev/null
+diff -up dhcp-4.2.0/common/dispatch.c.dracut dhcp-4.2.0/common/dispatch.c
+--- dhcp-4.2.0/common/dispatch.c.dracut 2010-06-01 19:29:59.000000000 +0200
++++ dhcp-4.2.0/common/dispatch.c 2010-07-21 16:10:09.000000000 +0200
+@@ -189,6 +189,10 @@ void add_timeout (when, where, what, ref
+ 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) {
--- /dev/null
+diff -up dhcp-4.2.0/client/clparse.c.requested dhcp-4.2.0/client/clparse.c
+--- dhcp-4.2.0/client/clparse.c.requested 2010-07-21 13:29:05.000000000 +0200
++++ dhcp-4.2.0/client/clparse.c 2010-07-21 13:50:29.000000000 +0200
+@@ -37,7 +37,7 @@
+
+ struct client_config top_level_config;
+
+-#define NUM_DEFAULT_REQUESTED_OPTS 9
++#define NUM_DEFAULT_REQUESTED_OPTS 14
+ struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
+
+ static void parse_client_default_duid(struct parse *cfile);
+@@ -111,6 +111,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 "
--- /dev/null
+diff -up dhcp-4.2.0/client/dhclient.c.backoff dhcp-4.2.0/client/dhclient.c
+--- dhcp-4.2.0/client/dhclient.c.backoff 2010-07-21 13:37:03.000000000 +0200
++++ dhcp-4.2.0/client/dhclient.c 2010-07-21 13:38:31.000000000 +0200
+@@ -1208,6 +1208,8 @@ void state_init (cpp)
+ void *cpp;
+ {
+ struct client_state *client = cpp;
++ enum dhcp_state init_state = client->state;
++ struct timeval tv;
+
+ ASSERT_STATE(state, S_INIT);
+
+@@ -1220,9 +1222,18 @@ void state_init (cpp)
+ client -> first_sending = cur_time;
+ client -> interval = client -> config -> initial_interval;
+
+- /* Add an immediate timeout to cause the first DHCPDISCOVER packet
+- to go out. */
+- send_discover (client);
++ if (init_state != S_DECLINED) {
++ /* Add an immediate timeout to cause the first DHCPDISCOVER packet
++ to go out. */
++ send_discover(client);
++ } else {
++ /* We've received an OFFER and it has been DECLINEd by dhclient-script.
++ * wait for a random time between 1 and backoff_cutoff seconds before
++ * trying again. */
++ tv . tv_sec = cur_time + ((1 + (random() >> 2)) % client->config->backoff_cutoff);
++ tv . tv_usec = 0;
++ add_timeout(&tv, send_discover, client, 0, 0);
++ }
+ }
+
+ /*
+@@ -1501,6 +1512,7 @@ void bind_lease (client)
+ send_decline (client);
+ destroy_client_lease (client -> new);
+ client -> new = (struct client_lease *)0;
++ client -> state = S_DECLINED;
+ state_init (client);
+ return;
+ }
+@@ -3711,6 +3723,7 @@ void client_location_changed ()
+ case S_INIT:
+ case S_REBINDING:
+ case S_STOPPED:
++ case S_DECLINED:
+ break;
+ }
+ client -> state = S_INIT;
+diff -up dhcp-4.2.0/includes/dhcpd.h.backoff dhcp-4.2.0/includes/dhcpd.h
+--- dhcp-4.2.0/includes/dhcpd.h.backoff 2010-07-21 13:29:05.000000000 +0200
++++ dhcp-4.2.0/includes/dhcpd.h 2010-07-21 13:38:31.000000000 +0200
+@@ -1056,7 +1056,8 @@ enum dhcp_state {
+ S_BOUND = 5,
+ S_RENEWING = 6,
+ S_REBINDING = 7,
+- S_STOPPED = 8
++ S_STOPPED = 8,
++ S_DECLINED = 9
+ };
+
+ /* Authentication and BOOTP policy possibilities (not all values work
--- /dev/null
+diff -up dhcp-4.2.0/omapip/errwarn.c.errwarn dhcp-4.2.0/omapip/errwarn.c
+--- dhcp-4.2.0/omapip/errwarn.c.errwarn 2009-07-23 20:52:21.000000000 +0200
++++ dhcp-4.2.0/omapip/errwarn.c 2010-07-21 13:23:47.000000000 +0200
+@@ -76,20 +76,13 @@ void log_fatal (const char * fmt, ... )
+
+ #if !defined (NOMINUM)
+ log_error ("%s", "");
+- log_error ("If you did not get this software from ftp.isc.org, please");
+- log_error ("get the latest from ftp.isc.org and install that before");
+- log_error ("requesting help.");
++ 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 ("If you did get this software from ftp.isc.org and have not");
+- log_error ("yet read the README, please read it before requesting help.");
+- log_error ("If you intend to request help from the dhcp-server@isc.org");
+- log_error ("mailing list, please read the section on the README about");
+- log_error ("submitting bug reports and requests for help.");
+- log_error ("%s", "");
+- log_error ("Please do not under any circumstances send requests for");
+- log_error ("help directly to the authors of this software - please");
+- log_error ("send them to the appropriate mailing list as described in");
+- log_error ("the README file.");
++ log_error ("Please report for this software via the Red Hat Bugzilla site:");
++ log_error (" http://bugzilla.redhat.com");
+ log_error ("%s", "");
+ log_error ("exiting.");
+ #endif
--- /dev/null
+diff -up dhcp-4.2.0/common/tables.c.garbage dhcp-4.2.0/common/tables.c
+--- dhcp-4.2.0/common/tables.c.garbage 2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.0/common/tables.c 2010-07-21 14:40:56.000000000 +0200
+@@ -207,7 +207,7 @@ static struct option dhcp_options[] = {
+ { "netinfo-server-tag", "t", &dhcp_universe, 113, 1 },
+ { "default-url", "t", &dhcp_universe, 114, 1 },
+ { "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
--- /dev/null
+diff -up dhcp-4.2.0/client/dhc6.c.honor-expired dhcp-4.2.0/client/dhc6.c
+--- dhcp-4.2.0/client/dhc6.c.honor-expired 2010-10-07 12:55:37.000000000 +0200
++++ dhcp-4.2.0/client/dhc6.c 2010-10-07 12:56:43.000000000 +0200
+@@ -1405,6 +1405,32 @@ start_info_request6(struct client_state
+ go_daemon();
+ }
+
++/* Run through the addresses in lease and return true if there's any unexpired.
++ * Return false otherwise.
++ */
++isc_boolean_t
++unexpired_address_in_lease(struct dhc6_lease *lease)
++{
++ struct dhc6_ia *ia;
++ struct dhc6_addr *addr;
++
++ for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
++ for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
++ if (addr->flags & DHC6_ADDR_EXPIRED)
++ continue;
++
++ if (addr->starts + addr->max_life > cur_time) {
++ return ISC_TRUE;
++ }
++ }
++ }
++
++ log_info("PRC: Previous lease is devoid of active addresses."
++ " Re-initializing.");
++
++ return ISC_FALSE;
++}
++
+ /*
+ * start_confirm6() kicks off an "init-reboot" version of the process, at
+ * startup to find out if old bindings are 'fair' and at runtime whenever
+@@ -1417,8 +1446,10 @@ start_confirm6(struct client_state *clie
+
+ /* If there is no active lease, there is nothing to check. */
+ if ((client->active_lease == NULL) ||
+- !active_prefix(client) ||
+- client->active_lease->released) {
++ !active_prefix(client) ||
++ client->active_lease->released ||
++ !unexpired_address_in_lease(client->active_lease)) {
++ dhc6_lease_destroy(&client->active_lease, MDL);
+ start_init6(client);
+ return;
+ }
--- /dev/null
+diff -up dhcp-4.2.0/client/dhclient.c.inherit dhcp-4.2.0/client/dhclient.c
+--- dhcp-4.2.0/client/dhclient.c.inherit 2010-07-21 14:33:44.000000000 +0200
++++ dhcp-4.2.0/client/dhclient.c 2010-07-21 14:40:05.000000000 +0200
+@@ -2322,6 +2322,7 @@ void send_request (cpp)
+ {
+ struct client_state *client = cpp;
+
++ int i;
+ int result;
+ int interval;
+ struct sockaddr_in destination;
+@@ -2381,6 +2382,22 @@ void send_request (cpp)
+ /* Now do a preinit on the interface so that we can
+ discover a new address. */
+ script_init (client, "PREINIT", (struct string_list *)0);
++
++ /* Has an active lease */
++ if (client -> interface -> addresses != NULL) {
++ for (i = 0; i < client -> interface -> address_count; i++) {
++ if (client -> active &&
++ client -> active -> is_bootp &&
++ client -> active -> expiry > cur_time &&
++ client -> interface -> addresses[i].s_addr != 0 &&
++ client -> active -> address.len == 4 &&
++ memcpy (client -> active -> address.iabuf, &(client -> interface -> addresses[i]), 4) == 0) {
++ client_envadd (client, "", "keep_old_ip", "%s", "yes");
++ break;
++ }
++ }
++ }
++
+ if (client -> alias)
+ script_write_params (client, "alias_",
+ client -> alias);
--- /dev/null
+diff -up dhcp-4.2.0/client/dhclient.c.logpid dhcp-4.2.0/client/dhclient.c
+--- dhcp-4.2.0/client/dhclient.c.logpid 2010-07-21 16:13:52.000000000 +0200
++++ dhcp-4.2.0/client/dhclient.c 2010-07-21 16:16:51.000000000 +0200
+@@ -154,7 +154,7 @@ main(int argc, char **argv) {
+ else if (fd != -1)
+ close(fd);
+
+- openlog("dhclient", LOG_NDELAY, LOG_DAEMON);
++ openlog("dhclient", LOG_NDELAY | LOG_PID, LOG_DAEMON);
+
+ #if !(defined(DEBUG) || defined(__CYGWIN32__))
+ setlogmask(LOG_UPTO(LOG_INFO));
--- /dev/null
+diff -up dhcp-4.2.0/common/discover.c.noipv6 dhcp-4.2.0/common/discover.c
+--- dhcp-4.2.0/common/discover.c.noipv6 2010-07-21 14:31:13.000000000 +0200
++++ dhcp-4.2.0/common/discover.c 2010-07-21 16:04:57.000000000 +0200
+@@ -443,7 +443,7 @@ begin_iface_scan(struct iface_conf_list
+ }
+
+ #ifdef DHCPv6
+- if (local_family == AF_INET6) {
++ if ((local_family == AF_INET6) && !access("/proc/net/if_inet6", R_OK)) {
+ ifaces->fp6 = fopen("/proc/net/if_inet6", "re");
+ if (ifaces->fp6 == NULL) {
+ log_error("Error opening '/proc/net/if_inet6' to "
+@@ -454,6 +454,8 @@ begin_iface_scan(struct iface_conf_list
+ ifaces->fp = NULL;
+ return 0;
+ }
++ } else {
++ ifaces->fp6 = NULL;
+ }
+ #endif
+
+@@ -721,7 +723,7 @@ next_iface(struct iface_info *info, int
+ return 1;
+ }
+ #ifdef DHCPv6
+- if (!(*err)) {
++ if (!(*err) && ifaces->fp6) {
+ if (local_family == AF_INET6)
+ return next_iface6(info, err, ifaces);
+ }
+@@ -740,7 +742,8 @@ end_iface_scan(struct iface_conf_list *i
+ ifaces->sock = -1;
+ #ifdef DHCPv6
+ if (local_family == AF_INET6) {
+- fclose(ifaces->fp6);
++ if (ifaces->fp6)
++ fclose(ifaces->fp6);
+ ifaces->fp6 = NULL;
+ }
+ #endif
--- /dev/null
+diff -up dhcp-4.2.0/server/dhcpv6.c.noprefixavail dhcp-4.2.0/server/dhcpv6.c
+--- dhcp-4.2.0/server/dhcpv6.c.noprefixavail 2010-10-07 13:48:45.000000000 +0200
++++ dhcp-4.2.0/server/dhcpv6.c 2010-10-13 11:00:25.000000000 +0200
+@@ -1134,7 +1134,7 @@ try_client_v6_prefix(struct iasubopt **p
+ return DHCP_R_INVALIDARG;
+ }
+ tmp_plen = (int) requested_pref->data[0];
+- if ((tmp_plen < 3) || (tmp_plen > 128)) {
++ if ((tmp_plen < 3) || (tmp_plen > 128) ||((int)tmp_plen != pool->units)) {
+ return ISC_R_FAILURE;
+ }
+ memcpy(&tmp_pref, requested_pref->data + 1, sizeof(tmp_pref));
+@@ -1147,9 +1147,8 @@ try_client_v6_prefix(struct iasubopt **p
+ return ISC_R_FAILURE;
+ }
+
+- if (((int)tmp_plen != pool->units) ||
+- !ipv6_in_pool(&tmp_pref, pool)) {
+- return ISC_R_FAILURE;
++ if (!ipv6_in_pool(&tmp_pref, pool)) {
++ return ISC_R_ADDRNOTAVAIL;
+ }
+
+ if (prefix6_exists(pool, &tmp_pref, tmp_plen)) {
+@@ -1409,13 +1408,6 @@ lease_to_client(struct data_string *repl
+ if ((status != ISC_R_SUCCESS) &&
+ (status != ISC_R_NORESOURCES))
+ goto exit;
+-
+- /*
+- * If any prefix cannot be given to any IA_PD, then
+- * set the NoPrefixAvail status code.
+- */
+- if (reply.client_resources == 0)
+- no_resources_avail = ISC_TRUE;
+ }
+
+ /*
+@@ -1549,36 +1541,6 @@ lease_to_client(struct data_string *repl
+ reply.opt_state, reply.packet,
+ required_opts_NAA,
+ NULL);
+- } else if (no_resources_avail && (reply.ia_count == 0) &&
+- (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
+- {
+- /* Set the NoPrefixAvail status code. */
+- if (!set_status_code(STATUS_NoPrefixAvail,
+- "No prefixes available for this "
+- "interface.", reply.opt_state)) {
+- log_error("lease_to_client: Unable to set "
+- "NoPrefixAvail status code.");
+- goto exit;
+- }
+-
+- /* Rewind the cursor to the start. */
+- reply.cursor = REPLY_OPTIONS_INDEX;
+-
+- /*
+- * Produce an advertise that includes only:
+- *
+- * Status code.
+- * Server DUID.
+- * Client DUID.
+- */
+- reply.buf.reply.msg_type = DHCPV6_ADVERTISE;
+- reply.cursor += store_options6((char *)reply.buf.data +
+- reply.cursor,
+- sizeof(reply.buf) -
+- reply.cursor,
+- reply.opt_state, reply.packet,
+- required_opts_NAA,
+- NULL);
+ } else {
+ /*
+ * Having stored the client's IA's, store any options that
+@@ -2793,16 +2755,18 @@ find_client_temporaries(struct reply_sta
+ */
+ static isc_result_t
+ reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
+- isc_result_t status = ISC_R_NORESOURCES;
++ isc_result_t status = ISC_R_ADDRNOTAVAIL;
+ struct ipv6_pool *pool;
+ int i;
+ struct data_string data_addr;
+
+ if ((reply == NULL) || (reply->shared == NULL) ||
+- (reply->shared->ipv6_pools == NULL) || (addr == NULL) ||
+- (reply->lease != NULL))
++ (addr == NULL) || (reply->lease != NULL))
+ return DHCP_R_INVALIDARG;
+
++ if (reply->shared->ipv6_pools == NULL)
++ return ISC_R_ADDRNOTAVAIL;
++
+ memset(&data_addr, 0, sizeof(data_addr));
+ data_addr.len = addr->len;
+ data_addr.data = addr->iabuf;
+@@ -3314,7 +3278,9 @@ reply_process_ia_pd(struct reply_state *
+ if (status == ISC_R_CANCELED)
+ break;
+
+- if ((status != ISC_R_SUCCESS) && (status != ISC_R_ADDRINUSE))
++ if ((status != ISC_R_SUCCESS) &&
++ (status != ISC_R_ADDRINUSE) &&
++ (status != ISC_R_ADDRNOTAVAIL))
+ goto cleanup;
+ }
+
+@@ -3594,7 +3560,8 @@ reply_process_prefix(struct reply_state
+
+ /* Either error out or skip this prefix. */
+ if ((status != ISC_R_SUCCESS) &&
+- (status != ISC_R_ADDRINUSE))
++ (status != ISC_R_ADDRINUSE) &&
++ (status != ISC_R_ADDRNOTAVAIL))
+ goto cleanup;
+
+ if (reply->lease == NULL) {
+@@ -3773,16 +3740,18 @@ prefix_is_owned(struct reply_state *repl
+ static isc_result_t
+ reply_process_try_prefix(struct reply_state *reply,
+ struct iaddrcidrnet *pref) {
+- isc_result_t status = ISC_R_NORESOURCES;
++ isc_result_t status = ISC_R_ADDRNOTAVAIL;
+ struct ipv6_pool *pool;
+ int i;
+ struct data_string data_pref;
+
+ if ((reply == NULL) || (reply->shared == NULL) ||
+- (reply->shared->ipv6_pools == NULL) || (pref == NULL) ||
+- (reply->lease != NULL))
++ (pref == NULL) || (reply->lease != NULL))
+ return DHCP_R_INVALIDARG;
+
++ if (reply->shared->ipv6_pools == NULL)
++ return ISC_R_ADDRNOTAVAIL;
++
+ memset(&data_pref, 0, sizeof(data_pref));
+ data_pref.len = 17;
+ if (!buffer_allocate(&data_pref.buffer, data_pref.len, MDL)) {
--- /dev/null
+diff -up dhcp-4.2.0/includes/dhcpd.h.paths dhcp-4.2.0/includes/dhcpd.h
+--- dhcp-4.2.0/includes/dhcpd.h.paths 2010-07-21 13:55:42.000000000 +0200
++++ dhcp-4.2.0/includes/dhcpd.h 2010-07-21 14:29:57.000000000 +0200
+@@ -1390,15 +1390,15 @@ 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
+-#define _PATH_DHCPD_DB LOCALSTATEDIR"/db/dhcpd.leases"
++#define _PATH_DHCPD_DB LOCALSTATEDIR"/dhcpd/dhcpd.leases"
+ #endif
+
+ #ifndef _PATH_DHCPD6_DB
+-#define _PATH_DHCPD6_DB LOCALSTATEDIR"/db/dhcpd6.leases"
++#define _PATH_DHCPD6_DB LOCALSTATEDIR"/dhcpd/dhcpd6.leases"
+ #endif
+
+ #ifndef _PATH_DHCPD_PID
+@@ -1412,7 +1412,7 @@ 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
+@@ -1428,11 +1428,11 @@ typedef unsigned char option_mask [16];
+ #endif
+
+ #ifndef _PATH_DHCLIENT_DB
+-#define _PATH_DHCLIENT_DB LOCALSTATEDIR"/db/dhclient.leases"
++#define _PATH_DHCLIENT_DB LOCALSTATEDIR"/dhclient/dhclient.leases"
+ #endif
+
+ #ifndef _PATH_DHCLIENT6_DB
+-#define _PATH_DHCLIENT6_DB LOCALSTATEDIR"/db/dhclient6.leases"
++#define _PATH_DHCLIENT6_DB LOCALSTATEDIR"/dhclient/dhclient6.leases"
+ #endif
+
+ #ifndef _PATH_RESOLV_CONF
--- /dev/null
+diff -up dhcp-4.2.0/client/dhclient.c.ifup dhcp-4.2.0/client/dhclient.c
+--- dhcp-4.2.0/client/dhclient.c.ifup 2010-07-21 13:30:10.000000000 +0200
++++ dhcp-4.2.0/client/dhclient.c 2010-07-21 13:37:03.000000000 +0200
+@@ -497,9 +497,81 @@ main(int argc, char **argv) {
+ kill(oldpid, SIGTERM);
+ }
+ 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);
--- /dev/null
+diff -up dhcp-4.2.0/server/bootp.c.unicast dhcp-4.2.0/server/bootp.c
+--- dhcp-4.2.0/server/bootp.c.unicast 2009-11-20 02:49:03.000000000 +0100
++++ dhcp-4.2.0/server/bootp.c 2010-07-21 13:40:25.000000000 +0200
+@@ -58,6 +58,7 @@ void bootp (packet)
+ char msgbuf [1024];
+ int ignorep;
+ int peer_has_leases = 0;
++ int norelay = 0;
+
+ if (packet -> raw -> op != BOOTREQUEST)
+ return;
+@@ -73,7 +74,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;
+ }
+@@ -390,6 +391,13 @@ void bootp (packet)
+ from, &to, &hto);
+ goto out;
+ }
++ } else if (norelay == 2) {
++ to.sin_addr = raw.ciaddr;
++ to.sin_port = remote_port;
++ if (fallback_interface) {
++ result = send_packet (fallback_interface, (struct packet *)0, &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 -up dhcp-4.2.0/server/dhcp.c.unicast dhcp-4.2.0/server/dhcp.c
+--- dhcp-4.2.0/server/dhcp.c.unicast 2010-06-01 19:29:59.000000000 +0200
++++ dhcp-4.2.0/server/dhcp.c 2010-07-21 13:40:25.000000000 +0200
+@@ -4185,6 +4185,7 @@ int locate_network (packet)
+ struct data_string data;
+ struct subnet *subnet = (struct subnet *)0;
+ struct option_cache *oc;
++ int norelay = 0;
+
+ /* See if there's a Relay Agent Link Selection Option, or a
+ * Subnet Selection Option. The Link-Select and Subnet-Select
+@@ -4200,12 +4201,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,
+@@ -4228,7 +4241,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. */
+@@ -4236,7 +4252,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. */
--- /dev/null
+diff -up dhcp-4.2.1b1/common/dispatch.c.64-bit_lease_parse dhcp-4.2.1b1/common/dispatch.c
+diff -up dhcp-4.2.1b1/common/parse.c.64-bit_lease_parse dhcp-4.2.1b1/common/parse.c
+--- dhcp-4.2.1b1/common/parse.c.64-bit_lease_parse 2010-12-30 00:01:42.000000000 +0100
++++ dhcp-4.2.1b1/common/parse.c 2011-01-28 08:01:10.000000000 +0100
+@@ -909,8 +909,8 @@ TIME
+ parse_date_core(cfile)
+ struct parse *cfile;
+ {
+- int guess;
+- int tzoff, wday, year, mon, mday, hour, min, sec;
++ TIME guess;
++ long int tzoff, wday, year, mon, mday, hour, min, sec;
+ const char *val;
+ enum dhcp_token token;
+ static int months[11] = { 31, 59, 90, 120, 151, 181,
+@@ -936,7 +936,7 @@ parse_date_core(cfile)
+ }
+
+ token = next_token(&val, NULL, cfile); /* consume number */
+- guess = atoi(val);
++ guess = atol(val);
+
+ return((TIME)guess);
+ }
+@@ -948,7 +948,7 @@ parse_date_core(cfile)
+ return((TIME)0);
+ }
+ token = next_token(&val, NULL, cfile); /* consume day of week */
+- wday = atoi(val);
++ wday = atol(val);
+
+ /* Year... */
+ token = peek_token(&val, NULL, cfile);
+@@ -964,7 +964,7 @@ parse_date_core(cfile)
+ somebody invents a time machine, I think we can safely disregard
+ it. This actually works around a stupid Y2K bug that was present
+ in a very early beta release of dhcpd. */
+- year = atoi(val);
++ year = atol(val);
+ if (year > 1900)
+ year -= 1900;
+
+@@ -988,7 +988,7 @@ parse_date_core(cfile)
+ return((TIME)0);
+ }
+ token = next_token(&val, NULL, cfile); /* consume month */
+- mon = atoi(val) - 1;
++ mon = atol(val) - 1;
+
+ /* Slash separating month from day... */
+ token = peek_token(&val, NULL, cfile);
+@@ -1010,7 +1010,7 @@ parse_date_core(cfile)
+ return((TIME)0);
+ }
+ token = next_token(&val, NULL, cfile); /* consume day of month */
+- mday = atoi(val);
++ mday = atol(val);
+
+ /* Hour... */
+ token = peek_token(&val, NULL, cfile);
+@@ -1021,7 +1021,7 @@ parse_date_core(cfile)
+ return((TIME)0);
+ }
+ token = next_token(&val, NULL, cfile); /* consume hour */
+- hour = atoi(val);
++ hour = atol(val);
+
+ /* Colon separating hour from minute... */
+ token = peek_token(&val, NULL, cfile);
+@@ -1043,7 +1043,7 @@ parse_date_core(cfile)
+ return((TIME)0);
+ }
+ token = next_token(&val, NULL, cfile); /* consume minute */
+- min = atoi(val);
++ min = atol(val);
+
+ /* Colon separating minute from second... */
+ token = peek_token(&val, NULL, cfile);
+@@ -1065,13 +1065,13 @@ parse_date_core(cfile)
+ return((TIME)0);
+ }
+ token = next_token(&val, NULL, cfile); /* consume second */
+- sec = atoi(val);
++ sec = atol(val);
+
+ tzoff = 0;
+ token = peek_token(&val, NULL, cfile);
+ if (token == NUMBER) {
+ token = next_token(&val, NULL, cfile); /* consume tzoff */
+- tzoff = atoi(val);
++ tzoff = atol(val);
+ } else if (token != SEMI) {
+ token = next_token(&val, NULL, cfile);
+ parse_warn(cfile,
--- /dev/null
+diff -up dhcp-4.2.1b1/client/dhclient.conf.supersede dhcp-4.2.1b1/client/dhclient.conf
+--- dhcp-4.2.1b1/client/dhclient.conf.supersede 2010-09-15 01:03:56.000000000 +0200
++++ dhcp-4.2.1b1/client/dhclient.conf 2011-01-27 18:38:28.000000000 +0100
+@@ -4,7 +4,7 @@ send dhcp-lease-time 3600;
+ supersede domain-search "fugue.com", "home.vix.com";
+ prepend domain-name-servers 127.0.0.1;
+ request subnet-mask, broadcast-address, time-offset, routers,
+- domain-name, domain-name-servers, host-name;
++ domain-search, domain-name-servers, host-name;
+ require subnet-mask, domain-name-servers;
+ timeout 60;
+ retry 60;
--- /dev/null
+diff -up dhcp-4.2.1b1/client/dhclient.8.man dhcp-4.2.1b1/client/dhclient.8
+--- dhcp-4.2.1b1/client/dhclient.8.man 2010-07-14 22:09:34.000000000 +0200
++++ dhcp-4.2.1b1/client/dhclient.8 2011-01-27 18:19:07.000000000 +0100
+@@ -115,6 +115,33 @@ dhclient - Dynamic Host Configuration Pr
+ .B -w
+ ]
+ [
++.B -B
++]
++[
++.B -I
++.I dhcp-client-identifier
++]
++[
++.B -H
++.I host-name
++]
++[
++.B -F
++.I fqdn.fqdn
++]
++[
++.B -V
++.I vendor-class-identifier
++]
++[
++.B -R
++.I request-option-list
++]
++[
++.B -timeout
++.I timeout
++]
++[
+ .B -v
+ ]
+ [
+@@ -264,6 +291,69 @@ not to exit when it doesn't find any suc
+ 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 \-B
++Set the BOOTP broadcast flag in request packets so servers will always
++broadcast replies.
++
++.TP
++.BI \-I\ <dhcp-client-identifier>
++Specify the dhcp-client-identifier option to send to the DHCP server.
++
++.TP
++.BI \-H\ <host-name>
++Specify the host-name option to send to the DHCP server. The host-name
++string only contains the client's hostname prefix, to which the server will
++append the ddns-domainname or domain-name options, if any, to derive the
++fully qualified domain name of the client. The
++.B -H
++option cannot be used with the
++.B -F
++option.
++
++.TP
++.BI \-F\ <fqdn.fqdn>
++Specify the fqdn.fqdn option to send to the DHCP server. This option cannot
++be used with the
++.B -H
++option. The fqdn.fqdn option must specify the complete domain name of the
++client host, which the server may use for dynamic DNS updates.
++
++.TP
++.BI \-V\ <vendor-class-identifier>
++Specify the vendor-class-identifier option to send to the DHCP server.
++
++.TP
++.BI \-R\ <option>[,<option>...]
++Specify the list of options the client is to request from the server. The
++option list must be a single string consisting of option names separated
++by at least one command and optional space characters. The default option
++list is:
++
++.BR
++ subnet-mask, broadcast-address, time-offset, routers,
++.BR
++ domain-search, domain-name, domain-name-servers, host-name,
++.BR
++ nis-domain, nis-servers, ntp-servers, interface-mtu
++
++.TP
++.B -R
++option does not append options to the default request, it overrides the
++default request list. Keep this in mind if you want to request an
++additional option besides the default request list. You will have to
++specify all option names for the
++.B -R
++parameter.
++
++.TP
++.BI \-timeout\ <timeout>
++Specify the time after which
++.B dhclient
++will decide that no DHCP servers can be contacted when no responses have been
++received.
++
+ .TP
+ .BI \-n
+ Do not configure any interfaces. This is most likely to be useful in
+diff -up dhcp-4.2.1b1/client/dhclient.conf.5.man dhcp-4.2.1b1/client/dhclient.conf.5
+--- dhcp-4.2.1b1/client/dhclient.conf.5.man 2010-09-15 01:03:56.000000000 +0200
++++ dhcp-4.2.1b1/client/dhclient.conf.5 2011-01-27 18:22:56.000000000 +0100
+@@ -186,7 +186,8 @@ responding to the client send the client
+ 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.
+@@ -672,6 +673,17 @@ know the DHCP service(s) anycast MAC add
+ 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 is used on a laptop running NetBSD
+ 1.3. The laptop has an IP alias of 192.5.5.213, and has one
+@@ -697,7 +709,7 @@ interface "ep0" {
+ supersede domain-search "fugue.com", "rc.vix.com", "home.vix.com";
+ prepend domain-name-servers 127.0.0.1;
+ request subnet-mask, broadcast-address, time-offset, routers,
+- domain-name, domain-name-servers, host-name;
++ domain-search, domain-name, domain-name-servers, host-name;
+ require subnet-mask, domain-name-servers;
+ script "CLIENTBINDIR/dhclient-script";
+ media "media 10baseT/UTP", "media 10base2/BNC";
+diff -up dhcp-4.2.1b1/client/dhclient-script.8.man dhcp-4.2.1b1/client/dhclient-script.8
+--- dhcp-4.2.1b1/client/dhclient-script.8.man 2010-07-06 21:03:11.000000000 +0200
++++ dhcp-4.2.1b1/client/dhclient-script.8 2011-01-27 18:24:44.000000000 +0100
+@@ -47,7 +47,7 @@ customizations are needed, they should b
+ 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
+@@ -91,6 +91,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 -up dhcp-4.2.1b1/common/dhcp-options.5.man dhcp-4.2.1b1/common/dhcp-options.5
+--- dhcp-4.2.1b1/common/dhcp-options.5.man 2010-07-13 22:56:56.000000000 +0200
++++ dhcp-4.2.1b1/common/dhcp-options.5 2011-01-27 18:25:57.000000000 +0100
+@@ -913,6 +913,21 @@ classless IP routing - it does not inclu
+ 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 -up dhcp-4.2.1b1/server/dhcpd.conf.5.man dhcp-4.2.1b1/server/dhcpd.conf.5
+--- dhcp-4.2.1b1/server/dhcpd.conf.5.man 2010-07-06 21:03:12.000000000 +0200
++++ dhcp-4.2.1b1/server/dhcpd.conf.5 2011-01-27 18:29:12.000000000 +0100
+@@ -519,6 +519,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
+@@ -533,9 +536,9 @@ primary server might look like this:
+ failover peer "foo" {
+ primary;
+ address anthrax.rc.vix.com;
+- port 519;
++ port 647;
+ peer address trantor.rc.vix.com;
+- peer port 520;
++ peer port 847;
+ max-response-delay 60;
+ max-unacked-updates 10;
+ mclt 3600;
+@@ -1305,7 +1308,7 @@ the zone containing PTR records - for IS
+ .PP
+ .nf
+ key DHCP_UPDATER {
+- algorithm HMAC-MD5.SIG-ALG.REG.INT;
++ algorithm hmac-md5;
+ secret pRP5FapFoJ95JEL06sv4PQ==;
+ };
+
+@@ -1328,7 +1331,7 @@ dhcpd.conf file:
+ .PP
+ .nf
+ key DHCP_UPDATER {
+- algorithm HMAC-MD5.SIG-ALG.REG.INT;
++ algorithm hmac-md5;
+ secret pRP5FapFoJ95JEL06sv4PQ==;
+ };
+
+@@ -2540,7 +2543,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
--- /dev/null
+diff -up dhcp-4.2.1b1/client/dhc6.c.retransmission dhcp-4.2.1b1/client/dhc6.c
+--- dhcp-4.2.1b1/client/dhc6.c.retransmission 2011-01-28 08:40:56.000000000 +0100
++++ dhcp-4.2.1b1/client/dhc6.c 2011-01-28 08:39:22.000000000 +0100
+@@ -361,7 +361,7 @@ dhc6_retrans_init(struct client_state *c
+ static void
+ dhc6_retrans_advance(struct client_state *client)
+ {
+- struct timeval elapsed;
++ struct timeval elapsed, elapsed_after_RT;
+
+ /* elapsed = cur - start */
+ elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
+@@ -378,6 +378,8 @@ dhc6_retrans_advance(struct client_state
+ elapsed.tv_sec += 1;
+ elapsed.tv_usec -= 1000000;
+ }
++ elapsed_after_RT.tv_sec = elapsed.tv_sec;
++ elapsed_after_RT.tv_usec = elapsed.tv_usec;
+
+ /*
+ * RT for each subsequent message transmission is based on the previous
+@@ -415,13 +417,10 @@ dhc6_retrans_advance(struct client_state
+ elapsed.tv_usec -= 1000000;
+ }
+ if (elapsed.tv_sec >= client->MRD) {
+- /*
+- * wake at RT + cur = start + MRD
+- */
+- client->RT = client->MRD +
+- (client->start_time.tv_sec - cur_tv.tv_sec);
+- client->RT = client->RT * 100 +
+- (client->start_time.tv_usec - cur_tv.tv_usec) / 10000;
++ client->RT = client->MRD - elapsed_after_RT.tv_sec;
++ client->RT = client->RT * 100 - elapsed_after_RT.tv_usec / 10000;
++ if (client->RT < 0)
++ client->RT = 0;
+ }
+ client->txcount++;
+ }
+@@ -1497,7 +1496,7 @@ check_timing6 (struct client_state *clie
+ }
+
+ /* Check if finished (-1 argument). */
+- if ((client->MRD != 0) && (elapsed.tv_sec > client->MRD)) {
++ if ((client->MRD != 0) && (elapsed.tv_sec >= client->MRD)) {
+ log_info("Max retransmission duration exceeded.");
+ return(CHK_TIM_MRD_EXCEEDED);
+ }
--- /dev/null
+diff -up dhcp-4.2.1-P1/client/dhc6.c.sendDecline dhcp-4.2.1-P1/client/dhc6.c
+--- dhcp-4.2.1-P1/client/dhc6.c.sendDecline 2010-09-10 22:27:11.000000000 +0200
++++ dhcp-4.2.1-P1/client/dhc6.c 2011-06-17 14:19:48.992099868 +0200
+@@ -95,6 +95,8 @@ void do_select6(void *input);
+ void do_refresh6(void *input);
+ static void do_release6(void *input);
+ static void start_bound(struct client_state *client);
++static void start_decline6(struct client_state *client);
++static void do_decline6(void *input);
+ static void start_informed(struct client_state *client);
+ void informed_handler(struct packet *packet, struct client_state *client);
+ void bound_handler(struct packet *packet, struct client_state *client);
+@@ -2075,6 +2077,7 @@ start_release6(struct client_state *clie
+ cancel_timeout(do_select6, client);
+ cancel_timeout(do_refresh6, client);
+ cancel_timeout(do_release6, client);
++ cancel_timeout(do_decline6, client);
+ client->state = S_STOPPED;
+
+ /*
+@@ -2708,6 +2711,7 @@ dhc6_check_reply(struct client_state *cl
+ break;
+
+ case S_STOPPED:
++ case S_DECLINED:
+ action = dhc6_stop_action;
+ break;
+
+@@ -2809,6 +2813,7 @@ dhc6_check_reply(struct client_state *cl
+ break;
+
+ case S_STOPPED:
++ case S_DECLINED:
+ /* Nothing critical to do at this stage. */
+ break;
+
+@@ -3799,17 +3804,23 @@ reply_handler(struct packet *packet, str
+ cancel_timeout(do_select6, client);
+ cancel_timeout(do_refresh6, client);
+ cancel_timeout(do_release6, client);
++ cancel_timeout(do_decline6, client);
+
+ /* If this is in response to a Release/Decline, clean up and return. */
+- if (client->state == S_STOPPED) {
+- if (client->active_lease == NULL)
+- return;
++ if ((client->state == S_STOPPED) ||
++ (client->state == S_DECLINED)) {
++
++ if (client->active_lease != NULL) {
++ dhc6_lease_destroy(&client->active_lease, MDL);
++ client->active_lease = NULL;
++ /* We should never wait for nothing!? */
++ if (stopping_finished())
++ exit(0);
++ }
++
++ if (client->state == S_DECLINED)
++ start_init6(client);
+
+- dhc6_lease_destroy(&client->active_lease, MDL);
+- client->active_lease = NULL;
+- /* We should never wait for nothing!? */
+- if (stopping_finished())
+- exit(0);
+ return;
+ }
+
+@@ -4336,7 +4347,11 @@ start_bound(struct client_state *client)
+ oldia, oldaddr);
+ dhc6_marshall_values("new_", client, lease, ia, addr);
+
+- script_go(client);
++ // when script returns 3, DAD failed
++ if (script_go(client) == 3) {
++ start_decline6(client);
++ return;
++ }
+ }
+
+ /* XXX: maybe we should loop on the old values instead? */
+@@ -4382,6 +4397,149 @@ start_bound(struct client_state *client)
+ dhc6_check_times(client);
+ }
+
++/*
++ * Decline addresses.
++ */
++void
++start_decline6(struct client_state *client)
++{
++ /* Cancel any pending transmissions */
++ cancel_timeout(do_confirm6, client);
++ cancel_timeout(do_select6, client);
++ cancel_timeout(do_refresh6, client);
++ cancel_timeout(do_release6, client);
++ cancel_timeout(do_decline6, client);
++ client->state = S_DECLINED;
++
++ if (client->active_lease == NULL)
++ return;
++
++ /* Set timers per RFC3315 section 18.1.7. */
++ client->IRT = DEC_TIMEOUT * 100;
++ client->MRT = 0;
++ client->MRC = DEC_MAX_RC;
++ client->MRD = 0;
++
++ dhc6_retrans_init(client);
++ client->v6_handler = reply_handler;
++
++ client->refresh_type = DHCPV6_DECLINE;
++ do_decline6(client);
++}
++
++/*
++ * do_decline6() creates a Decline packet and transmits it.
++ */
++static void
++do_decline6(void *input)
++{
++ struct client_state *client;
++ struct data_string ds;
++ int send_ret;
++ struct timeval elapsed, tv;
++
++ client = input;
++
++ if ((client->active_lease == NULL) || !active_prefix(client))
++ return;
++
++ if ((client->MRC != 0) && (client->txcount > client->MRC)) {
++ log_info("Max retransmission count exceeded.");
++ goto decline_done;
++ }
++
++ /*
++ * Start_time starts at the first transmission.
++ */
++ if (client->txcount == 0) {
++ client->start_time.tv_sec = cur_tv.tv_sec;
++ client->start_time.tv_usec = cur_tv.tv_usec;
++ }
++
++ /* elapsed = cur - start */
++ elapsed.tv_sec = cur_tv.tv_sec - client->start_time.tv_sec;
++ elapsed.tv_usec = cur_tv.tv_usec - client->start_time.tv_usec;
++ if (elapsed.tv_usec < 0) {
++ elapsed.tv_sec -= 1;
++ elapsed.tv_usec += 1000000;
++ }
++
++ memset(&ds, 0, sizeof(ds));
++ if (!buffer_allocate(&ds.buffer, 4, MDL)) {
++ log_error("Unable to allocate memory for Decline.");
++ goto decline_done;
++ }
++
++ ds.data = ds.buffer->data;
++ ds.len = 4;
++ ds.buffer->data[0] = DHCPV6_DECLINE;
++ memcpy(ds.buffer->data + 1, client->dhcpv6_transaction_id, 3);
++
++ /* Form an elapsed option. */
++ /* Maximum value is 65535 1/100s coded as 0xffff. */
++ if ((elapsed.tv_sec < 0) || (elapsed.tv_sec > 655) ||
++ ((elapsed.tv_sec == 655) && (elapsed.tv_usec > 350000))) {
++ client->elapsed = 0xffff;
++ } else {
++ client->elapsed = elapsed.tv_sec * 100;
++ client->elapsed += elapsed.tv_usec / 10000;
++ }
++
++ client->elapsed = htons(client->elapsed);
++
++ log_debug("XMT: Forming Decline.");
++ make_client6_options(client, &client->sent_options,
++ client->active_lease, DHCPV6_DECLINE);
++ dhcpv6_universe.encapsulate(&ds, NULL, NULL, client, NULL,
++ client->sent_options, &global_scope,
++ &dhcpv6_universe);
++
++ /* Append IA's (but don't release temporary addresses). */
++ if (wanted_ia_na &&
++ dhc6_add_ia_na(client, &ds, client->active_lease,
++ DHCPV6_DECLINE) != ISC_R_SUCCESS) {
++ data_string_forget(&ds, MDL);
++ goto decline_done;
++ }
++ if (wanted_ia_pd &&
++ dhc6_add_ia_pd(client, &ds, client->active_lease,
++ DHCPV6_DECLINE) != ISC_R_SUCCESS) {
++ data_string_forget(&ds, MDL);
++ goto decline_done;
++ }
++
++ /* Transmit and wait. */
++ log_info("XMT: Decline on %s, interval %ld0ms.",
++ client->name ? client->name : client->interface->name,
++ (long int)client->RT);
++
++ send_ret = send_packet6(client->interface, ds.data, ds.len,
++ &DHCPv6DestAddr);
++ if (send_ret != ds.len) {
++ log_error("dhc6: sendpacket6() sent %d of %d bytes",
++ send_ret, ds.len);
++ }
++
++ data_string_forget(&ds, MDL);
++
++ /* Wait RT */
++ tv.tv_sec = cur_tv.tv_sec + client->RT / 100;
++ tv.tv_usec = cur_tv.tv_usec + (client->RT % 100) * 10000;
++ if (tv.tv_usec >= 1000000) {
++ tv.tv_sec += 1;
++ tv.tv_usec -= 1000000;
++ }
++ add_timeout(&tv, do_decline6, client, NULL, NULL);
++ dhc6_retrans_advance(client);
++ return;
++
++decline_done:
++ dhc6_lease_destroy(&client->active_lease, MDL);
++ client->active_lease = NULL;
++ start_init6(client);
++ return;
++}
++
+ /* While bound, ignore packets. In the future we'll want to answer
+ * Reconfigure-Request messages and the like.
+ */
--- /dev/null
+diff -up dhcp-4.2.2b1/client/clparse.c.cloexec dhcp-4.2.2b1/client/clparse.c
+--- dhcp-4.2.2b1/client/clparse.c.cloexec 2011-07-01 14:13:30.973887714 +0200
++++ dhcp-4.2.2b1/client/clparse.c 2011-07-01 14:15:15.021580693 +0200
+@@ -246,7 +246,7 @@ int read_client_conf_file (const char *n
+ 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;
+@@ -283,7 +283,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 -up dhcp-4.2.2b1/client/dhclient.c.cloexec dhcp-4.2.2b1/client/dhclient.c
+--- dhcp-4.2.2b1/client/dhclient.c.cloexec 2011-07-01 14:13:30.970887717 +0200
++++ dhcp-4.2.2b1/client/dhclient.c 2011-07-01 14:16:51.485930388 +0200
+@@ -148,11 +148,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)
+@@ -506,7 +506,7 @@ main(int argc, char **argv) {
+ int e;
+
+ oldpid = 0;
+- 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;
+
+@@ -548,7 +548,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;
+
+@@ -573,7 +573,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);
+@@ -2995,7 +2995,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;
+@@ -3105,7 +3105,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;
+@@ -3285,7 +3285,7 @@ int write_client_lease (client, lease, r
+ 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;
+@@ -3772,9 +3772,9 @@ void go_daemon ()
+ close(2);
+
+ /* Reopen them on /dev/null. */
+- open("/dev/null", O_RDWR);
+- open("/dev/null", O_RDWR);
+- open("/dev/null", O_RDWR);
++ open("/dev/null", O_RDWR | O_CLOEXEC);
++ open("/dev/null", O_RDWR | O_CLOEXEC);
++ open("/dev/null", O_RDWR | O_CLOEXEC);
+
+ write_client_pid_file ();
+
+@@ -3791,14 +3791,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 -up dhcp-4.2.2b1/common/bpf.c.cloexec dhcp-4.2.2b1/common/bpf.c
+--- dhcp-4.2.2b1/common/bpf.c.cloexec 2011-07-01 14:13:30.976887712 +0200
++++ dhcp-4.2.2b1/common/bpf.c 2011-07-01 14:13:31.030887673 +0200
+@@ -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 -up dhcp-4.2.2b1/common/discover.c.cloexec dhcp-4.2.2b1/common/discover.c
+--- dhcp-4.2.2b1/common/discover.c.cloexec 2011-06-27 18:18:20.000000000 +0200
++++ dhcp-4.2.2b1/common/discover.c 2011-07-01 14:13:31.031887673 +0200
+@@ -421,7 +421,7 @@ begin_iface_scan(struct iface_conf_list
+ int len;
+ int i;
+
+- ifaces->fp = fopen("/proc/net/dev", "r");
++ ifaces->fp = fopen("/proc/net/dev", "re");
+ if (ifaces->fp == NULL) {
+ log_error("Error opening '/proc/net/dev' to list interfaces");
+ return 0;
+@@ -456,7 +456,7 @@ begin_iface_scan(struct iface_conf_list
+
+ #ifdef DHCPv6
+ if (local_family == AF_INET6) {
+- ifaces->fp6 = fopen("/proc/net/if_inet6", "r");
++ ifaces->fp6 = fopen("/proc/net/if_inet6", "re");
+ if (ifaces->fp6 == NULL) {
+ log_error("Error opening '/proc/net/if_inet6' to "
+ "list IPv6 interfaces; %m");
+diff -up dhcp-4.2.2b1/common/dlpi.c.cloexec dhcp-4.2.2b1/common/dlpi.c
+--- dhcp-4.2.2b1/common/dlpi.c.cloexec 2011-07-01 14:13:30.977887712 +0200
++++ dhcp-4.2.2b1/common/dlpi.c 2011-07-01 14:13:31.032887673 +0200
+@@ -806,7 +806,7 @@ dlpiopen(const char *ifname) {
+ }
+ *dp = '\0';
+
+- return open (devname, O_RDWR, 0);
++ return open (devname, O_RDWR | O_CLOEXEC, 0);
+ }
+
+ /*
+diff -up dhcp-4.2.2b1/common/nit.c.cloexec dhcp-4.2.2b1/common/nit.c
+--- dhcp-4.2.2b1/common/nit.c.cloexec 2011-07-01 14:13:30.978887712 +0200
++++ dhcp-4.2.2b1/common/nit.c 2011-07-01 14:13:31.033887672 +0200
+@@ -81,7 +81,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 -up dhcp-4.2.2b1/common/resolv.c.cloexec dhcp-4.2.2b1/common/resolv.c
+--- dhcp-4.2.2b1/common/resolv.c.cloexec 2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/common/resolv.c 2011-07-01 14:13:31.033887672 +0200
+@@ -49,7 +49,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 -up dhcp-4.2.2b1/common/upf.c.cloexec dhcp-4.2.2b1/common/upf.c
+--- dhcp-4.2.2b1/common/upf.c.cloexec 2011-07-01 14:13:30.979887712 +0200
++++ dhcp-4.2.2b1/common/upf.c 2011-07-01 14:13:31.034887671 +0200
+@@ -77,7 +77,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 -up dhcp-4.2.2b1/dst/dst_api.c.cloexec dhcp-4.2.2b1/dst/dst_api.c
+--- dhcp-4.2.2b1/dst/dst_api.c.cloexec 2009-10-29 01:46:48.000000000 +0100
++++ dhcp-4.2.2b1/dst/dst_api.c 2011-07-01 14:13:31.035887670 +0200
+@@ -437,7 +437,7 @@ dst_s_write_private_key(const DST_KEY *k
+ PRIVATE_KEY, PATH_MAX);
+
+ /* Do not overwrite an existing file */
+- if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) {
++ if ((fp = dst_s_fopen(file, "we", 0600)) != NULL) {
+ int nn;
+ if ((nn = fwrite(encoded_block, 1, len, fp)) != len) {
+ EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n",
+@@ -494,7 +494,7 @@ dst_s_read_public_key(const char *in_nam
+ * flags, proto, alg stored as decimal (or hex numbers FIXME).
+ * (FIXME: handle parentheses for line continuation.)
+ */
+- if ((fp = dst_s_fopen(name, "r", 0)) == NULL) {
++ if ((fp = dst_s_fopen(name, "re", 0)) == NULL) {
+ EREPORT(("dst_read_public_key(): Public Key not found %s\n",
+ name));
+ return (NULL);
+@@ -620,7 +620,7 @@ dst_s_write_public_key(const DST_KEY *ke
+ return (0);
+ }
+ /* create public key file */
+- if ((fp = dst_s_fopen(filename, "w+", 0644)) == NULL) {
++ if ((fp = dst_s_fopen(filename, "w+e", 0644)) == NULL) {
+ EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n",
+ filename, errno));
+ return (0);
+@@ -854,7 +854,7 @@ dst_s_read_private_key_file(char *name,
+ return (0);
+ }
+ /* first check if we can find the key file */
+- if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) {
++ if ((fp = dst_s_fopen(filename, "re", 0)) == NULL) {
+ EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n",
+ filename, dst_path[0] ? dst_path :
+ (char *) getcwd(NULL, PATH_MAX - 1)));
+diff -up dhcp-4.2.2b1/dst/prandom.c.cloexec dhcp-4.2.2b1/dst/prandom.c
+--- dhcp-4.2.2b1/dst/prandom.c.cloexec 2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/dst/prandom.c 2011-07-01 14:13:31.035887670 +0200
+@@ -269,7 +269,7 @@ get_dev_random(u_char *output, unsigned
+
+ s = stat("/dev/random", &st);
+ if (s == 0 && S_ISCHR(st.st_mode)) {
+- if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) != -1) {
++ if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK | O_CLOEXEC)) != -1) {
+ if ((n = read(fd, output, size)) < 0)
+ n = 0;
+ close(fd);
+@@ -480,7 +480,7 @@ digest_file(dst_work *work)
+ work->file_digest = dst_free_key(work->file_digest);
+ return (0);
+ }
+- if ((fp = fopen(name, "r")) == NULL)
++ if ((fp = fopen(name, "re")) == NULL)
+ return (0);
+ for (no = 0; (i = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0;
+ no += i)
+diff -up dhcp-4.2.2b1/omapip/trace.c.cloexec dhcp-4.2.2b1/omapip/trace.c
+--- dhcp-4.2.2b1/omapip/trace.c.cloexec 2010-05-27 02:34:57.000000000 +0200
++++ dhcp-4.2.2b1/omapip/trace.c 2011-07-01 14:13:31.036887669 +0200
+@@ -141,10 +141,10 @@ isc_result_t trace_begin (const char *fi
+ 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);
+ }
+
+@@ -431,7 +431,7 @@ void trace_file_replay (const char *file
+ 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 -up dhcp-4.2.2b1/relay/dhcrelay.c.cloexec dhcp-4.2.2b1/relay/dhcrelay.c
+--- dhcp-4.2.2b1/relay/dhcrelay.c.cloexec 2011-05-10 15:07:37.000000000 +0200
++++ dhcp-4.2.2b1/relay/dhcrelay.c 2011-07-01 14:18:07.630209767 +0200
+@@ -183,11 +183,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)
+@@ -540,13 +540,13 @@ main(int argc, char **argv) {
+
+ 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 -up dhcp-4.2.2b1/server/confpars.c.cloexec dhcp-4.2.2b1/server/confpars.c
+--- dhcp-4.2.2b1/server/confpars.c.cloexec 2010-10-14 00:34:45.000000000 +0200
++++ dhcp-4.2.2b1/server/confpars.c 2011-07-01 14:13:31.039887666 +0200
+@@ -116,7 +116,7 @@ isc_result_t read_conf_file (const char
+ }
+ #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 -up dhcp-4.2.2b1/server/db.c.cloexec dhcp-4.2.2b1/server/db.c
+--- dhcp-4.2.2b1/server/db.c.cloexec 2010-09-14 00:15:26.000000000 +0200
++++ dhcp-4.2.2b1/server/db.c 2011-07-01 14:13:31.040887665 +0200
+@@ -1035,7 +1035,7 @@ void db_startup (testp)
+ }
+ #endif
+ if (!testp) {
+- db_file = fopen (path_dhcpd_db, "a");
++ db_file = fopen (path_dhcpd_db, "ae");
+ if (!db_file)
+ log_fatal ("Can't open %s for append.", path_dhcpd_db);
+ expire_all_pools ();
+@@ -1083,12 +1083,12 @@ int new_lease_file ()
+ 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;
+ }
+- 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 -up dhcp-4.2.2b1/server/dhcpd.c.cloexec dhcp-4.2.2b1/server/dhcpd.c
+--- dhcp-4.2.2b1/server/dhcpd.c.cloexec 2011-04-21 16:08:15.000000000 +0200
++++ dhcp-4.2.2b1/server/dhcpd.c 2011-07-01 14:19:40.354124505 +0200
+@@ -270,11 +270,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)
+@@ -793,7 +793,7 @@ main(int argc, char **argv) {
+ */
+ if (no_pid_file == ISC_FALSE) {
+ /*Read previous pid file. */
+- if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
++ if ((i = open (path_dhcpd_pid, O_RDONLY | O_CLOEXEC)) >= 0) {
+ status = read(i, pbuf, (sizeof pbuf) - 1);
+ close (i);
+ if (status > 0) {
+@@ -812,7 +812,7 @@ main(int argc, char **argv) {
+ }
+
+ /* Write new pid file. */
+- 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)));
+@@ -840,9 +840,9 @@ main(int argc, char **argv) {
+ close(2);
+
+ /* Reopen them on /dev/null. */
+- open("/dev/null", O_RDWR);
+- open("/dev/null", O_RDWR);
+- open("/dev/null", O_RDWR);
++ open("/dev/null", O_RDWR | O_CLOEXEC);
++ open("/dev/null", O_RDWR | O_CLOEXEC);
++ open("/dev/null", O_RDWR | O_CLOEXEC);
+ log_perror = 0; /* No sense logging to /dev/null. */
+
+ IGNORE_RET (chdir("/"));
+diff -up dhcp-4.2.2b1/server/ldap.c.cloexec dhcp-4.2.2b1/server/ldap.c
+--- dhcp-4.2.2b1/server/ldap.c.cloexec 2010-03-25 16:26:58.000000000 +0100
++++ dhcp-4.2.2b1/server/ldap.c 2011-07-01 14:13:31.043887665 +0200
+@@ -685,7 +685,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));
--- /dev/null
+diff -up dhcp-4.2.2b1/client/dhclient.8.capability dhcp-4.2.2b1/client/dhclient.8
+--- dhcp-4.2.2b1/client/dhclient.8.capability 2011-07-01 15:09:06.603784531 +0200
++++ dhcp-4.2.2b1/client/dhclient.8 2011-07-01 15:09:06.663783913 +0200
+@@ -118,6 +118,9 @@ dhclient - Dynamic Host Configuration Pr
+ .B -w
+ ]
+ [
++.B -nc
++]
++[
+ .B -B
+ ]
+ [
+@@ -296,6 +299,32 @@ has been added or removed, so that the c
+ 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 \-B
+ Set the BOOTP broadcast flag in request packets so servers will always
+ broadcast replies.
+diff -up dhcp-4.2.2b1/client/dhclient.c.capability dhcp-4.2.2b1/client/dhclient.c
+--- dhcp-4.2.2b1/client/dhclient.c.capability 2011-07-01 15:09:06.644784107 +0200
++++ dhcp-4.2.2b1/client/dhclient.c 2011-07-01 15:09:06.664783903 +0200
+@@ -39,6 +39,10 @@
+ #include <limits.h>
+ #include <dns/result.h>
+
++#ifdef HAVE_LIBCAP_NG
++#include <cap-ng.h>
++#endif
++
+ /*
+ * Defined in stdio.h when _GNU_SOURCE is set, but we don't want to define
+ * that when building ISC code.
+@@ -141,6 +145,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));
+@@ -410,6 +417,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();
+ } else if (interfaces_requested < 0) {
+@@ -458,6 +469,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 -up dhcp-4.2.2b1/client/dhclient-script.8.capability dhcp-4.2.2b1/client/dhclient-script.8
+--- dhcp-4.2.2b1/client/dhclient-script.8.capability 2011-07-01 15:09:06.604784521 +0200
++++ dhcp-4.2.2b1/client/dhclient-script.8 2011-07-01 15:09:06.666783883 +0200
+@@ -239,6 +239,16 @@ repeatedly initialized to the values pro
+ 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 -up dhcp-4.2.2b1/client/Makefile.am.capability dhcp-4.2.2b1/client/Makefile.am
+--- dhcp-4.2.2b1/client/Makefile.am.capability 2011-07-01 15:09:06.526785327 +0200
++++ dhcp-4.2.2b1/client/Makefile.am 2011-07-01 15:09:06.667783873 +0200
+@@ -5,7 +5,7 @@ dhclient_SOURCES = clparse.c dhclient.c
+ scripts/netbsd scripts/nextstep scripts/openbsd \
+ scripts/solaris scripts/openwrt
+ dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+- $(BIND9_LIBDIR) -ldns-export -lisc-export
++ $(BIND9_LIBDIR) -ldns-export -lisc-export $(CAPNG_LDADD)
+ man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
+ EXTRA_DIST = $(man_MANS)
+
+diff -up dhcp-4.2.2b1/configure.ac.capability dhcp-4.2.2b1/configure.ac
+--- dhcp-4.2.2b1/configure.ac.capability 2011-07-01 15:09:06.527785317 +0200
++++ dhcp-4.2.2b1/configure.ac 2011-07-01 15:09:06.667783873 +0200
+@@ -449,6 +449,41 @@ AC_TRY_LINK(
+ # 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 -up dhcp-4.2.2b1/relay/dhcrelay.c.capability dhcp-4.2.2b1/relay/dhcrelay.c
+--- dhcp-4.2.2b1/relay/dhcrelay.c.capability 2011-07-01 15:09:06.626784295 +0200
++++ dhcp-4.2.2b1/relay/dhcrelay.c 2011-07-01 15:12:05.362223794 +0200
+@@ -36,6 +36,11 @@
+ #include <syslog.h>
+ #include <sys/time.h>
+
++#ifdef HAVE_LIBCAP_NG
++# include <cap-ng.h>
++ 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];
+@@ -356,6 +361,10 @@ main(int argc, char **argv) {
+ sl->next = upstreams;
+ upstreams = sl;
+ #endif
++ } else if (!strcmp(argv[i], "-nc")) {
++#ifdef HAVE_LIBCAP_NG
++ keep_capabilities = 1;
++#endif
+ } else if (!strcmp(argv[i], "-pf")) {
+ if (++i == argc)
+ usage();
+@@ -426,6 +435,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);
+@@ -573,6 +593,15 @@ main(int argc, char **argv) {
+ dhcpv6_packet_handler = do_packet6;
+ #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();
+
+diff -up dhcp-4.2.2b1/relay/Makefile.am.capability dhcp-4.2.2b1/relay/Makefile.am
+--- dhcp-4.2.2b1/relay/Makefile.am.capability 2011-07-01 15:09:06.546785121 +0200
++++ dhcp-4.2.2b1/relay/Makefile.am 2011-07-01 15:09:06.670783841 +0200
+@@ -3,7 +3,7 @@ AM_CPPFLAGS = -DLOCALSTATEDIR='"@localst
+ sbin_PROGRAMS = dhcrelay
+ dhcrelay_SOURCES = dhcrelay.c
+ dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+- $(BIND9_LIBDIR) -ldns-export -lisc-export
++ $(BIND9_LIBDIR) -ldns-export -lisc-export $(CAPNG_LDADD)
+ man_MANS = dhcrelay.8
+ EXTRA_DIST = $(man_MANS)
+
+diff -up dhcp-4.2.2b1/server/dhcpd.c.capability dhcp-4.2.2b1/server/dhcpd.c
+--- dhcp-4.2.2b1/server/dhcpd.c.capability 2011-07-01 15:09:06.636784192 +0200
++++ dhcp-4.2.2b1/server/dhcpd.c 2011-07-01 15:09:06.670783841 +0200
+@@ -58,6 +58,11 @@ static const char url [] =
+ # undef group
+ #endif /* PARANOIA */
+
++#ifdef HAVE_LIBCAP_NG
++# include <cap-ng.h>
++ int keep_capabilities = 0;
++#endif
++
+ static void usage(void);
+
+ struct iaddr server_identifier;
+@@ -403,6 +408,10 @@ main(int argc, char **argv) {
+ traceinfile = argv [i];
+ trace_replay_init ();
+ #endif /* TRACING */
++ } else if (!strcmp(argv[i], "-nc")) {
++#ifdef HAVE_LIBCAP_NG
++ keep_capabilities = 1;
++#endif
+ } else if (argv [i][0] == '-') {
+ usage ();
+ } else {
+@@ -459,6 +468,17 @@ main(int argc, char **argv) {
+ }
+ #endif /* DHCPv6 */
+
++#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, CAP_SYS_CHROOT, CAP_SETUID, CAP_SETGID, -1);
++ capng_apply(CAPNG_SELECT_BOTH);
++ log_info ("Dropped all unnecessary capabilities.");
++ }
++#endif
++
+ /*
+ * convert relative path names to absolute, for files that need
+ * to be reopened after chdir() has been called
+@@ -859,6 +879,15 @@ main(int argc, char **argv) {
+ omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
+ (omapi_object_t *)0, "state", server_running);
+
++#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
++
+ /* Receive packets and dispatch them... */
+ dispatch ();
+
+diff -up dhcp-4.2.2b1/server/Makefile.am.capability dhcp-4.2.2b1/server/Makefile.am
+--- dhcp-4.2.2b1/server/Makefile.am.capability 2011-07-01 15:09:06.546785121 +0200
++++ dhcp-4.2.2b1/server/Makefile.am 2011-07-01 15:09:06.671783830 +0200
+@@ -8,7 +8,8 @@ dhcpd_SOURCES = dhcpd.c dhcp.c bootp.c c
+
+ dhcpd_CFLAGS = $(LDAP_CFLAGS)
+ dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+- ../dhcpctl/libdhcpctl.a $(BIND9_LIBDIR) -ldns-export -lisc-export
++ ../dhcpctl/libdhcpctl.a $(BIND9_LIBDIR) -ldns-export -lisc-export \
++ $(CAPNG_LDADD)
+
+ man_MANS = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
+ EXTRA_DIST = $(man_MANS)
--- /dev/null
+diff -up dhcp-4.2.2b1/client/dhclient.c.usage dhcp-4.2.2b1/client/dhclient.c
+--- dhcp-4.2.2b1/client/dhclient.c.usage 2011-07-01 13:55:16.000000000 +0200
++++ dhcp-4.2.2b1/client/dhclient.c 2011-07-01 13:58:55.243800602 +0200
+@@ -1047,6 +1047,10 @@ static void usage()
+ " [-s server-addr] [-cf config-file] "
+ "[-lf lease-file]\n"
+ " [-pf pid-file] [--no-pid] [-e VAR=val]\n"
++ " [-I <dhcp-client-identifier>] [-B]\n"
++ " [-H <host-name> | -F <fqdn.fqdn>] [-timeout <timeout>]\n"
++ " [-V <vendor-class-identifier>]\n"
++ " [-R <request option list>]\n"
+ " [-sf script-file] [interface]");
+ }
+
--- /dev/null
+diff -up dhcp-4.2.2/client/dhclient.c.gpxe-cid dhcp-4.2.2/client/dhclient.c
+--- dhcp-4.2.2/client/dhclient.c.gpxe-cid 2011-09-16 18:23:20.190453902 +0200
++++ dhcp-4.2.2/client/dhclient.c 2011-09-16 18:27:15.568463599 +0200
+@@ -58,6 +58,13 @@ const char *path_dhclient_pid = NULL;
+ static char path_dhclient_script_array[] = _PATH_DHCLIENT_SCRIPT;
+ char *path_dhclient_script = path_dhclient_script_array;
+
++/* Default Prefix */
++static unsigned char default_prefix[12] = {
++ 0xff, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x02, 0x00,
++ 0x00, 0x02, 0xc9, 0x00
++};
++
+ /* False (default) => we write and use a pid file */
+ isc_boolean_t no_pid_file = ISC_FALSE;
+
+@@ -1250,6 +1257,12 @@ int find_subnet (struct subnet **sp,
+ static void setup_ib_interface(struct interface_info *ip)
+ {
+ struct group *g;
++ struct hardware *hw = &ip->hw_address;
++ char client_id[64];
++ char *arg_conf = NULL;
++ int arg_conf_len = 0;
++ isc_result_t status;
++ struct parse *cfile = (struct parse *)0;
+
+ /* Set the broadcast flag */
+ ip->client->config->bootp_broadcast_always = 1;
+@@ -1266,8 +1279,39 @@ static void setup_ib_interface(struct in
+ }
+ }
+
+- /* No client ID specified */
+- log_fatal("dhcp-client-identifier must be specified for InfiniBand");
++ /*
++ * No client ID specified, make up one based on a default
++ * "prefix" and the port GUID.
++ *
++ * NOTE: This is compatible with what gpxe does.
++ */
++ sprintf(client_id, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
++ default_prefix[0], default_prefix[1], default_prefix[2],
++ default_prefix[3], default_prefix[4], default_prefix[5],
++ default_prefix[6], default_prefix[7], default_prefix[8],
++ default_prefix[9], default_prefix[10], default_prefix[11],
++ hw->hbuf[1], hw->hbuf[2], hw->hbuf[3], hw->hbuf[4],
++ hw->hbuf[5], hw->hbuf[6], hw->hbuf[7], hw->hbuf[8]);
++
++ arg_conf_len = asprintf(&arg_conf,
++ "send dhcp-client-identifier %s;",
++ client_id);
++
++ if ((arg_conf == 0) || (arg_conf_len <= 0))
++ log_fatal("Unable to send option dhcp-client-identifier");
++
++ status = new_parse(&cfile, -1, arg_conf, arg_conf_len,
++ "Automatic Infiniband client identifier", 0);
++
++ if ((status != ISC_R_SUCCESS) || (cfile->warnings_occurred))
++ log_fatal("Failed to parse Infiniband client identifier");
++
++ parse_client_statement(cfile, NULL, ip->client->config);
++
++ if (cfile->warnings_occurred)
++ log_fatal("Failed to parse Infiniband client identifier");
++
++ end_parse(&cfile);
+ }
+
+ /* Individual States:
+diff -up dhcp-4.2.2/common/lpf.c.gpxe-cid dhcp-4.2.2/common/lpf.c
+--- dhcp-4.2.2/common/lpf.c.gpxe-cid 2011-09-16 18:23:20.183453996 +0200
++++ dhcp-4.2.2/common/lpf.c 2011-09-16 18:25:28.235804421 +0200
+@@ -591,6 +591,37 @@ void maybe_setup_fallback ()
+ }
+ }
+
++static unsigned char * get_ib_hw_addr(char * name)
++{
++ struct ifaddrs *ifaddrs;
++ struct ifaddrs *ifa;
++ struct sockaddr_ll *sll = NULL;
++ static unsigned char hw_addr[8];
++
++ if (getifaddrs(&ifaddrs) == -1)
++ return NULL;
++
++ 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) {
++ sll = (struct sockaddr_ll *)(void *)ifa->ifa_addr;
++ break;
++ }
++ }
++ if (sll == NULL) {
++ freeifaddrs(ifaddrs);
++ return NULL;
++ }
++ memcpy(hw_addr, &sll->sll_addr[sll->sll_halen - 8], 8);
++ freeifaddrs(ifaddrs);
++ return (unsigned char *)&hw_addr;
++}
++
+ void
+ get_hw_addr(struct interface_info *info)
+ {
+@@ -599,6 +630,7 @@ get_hw_addr(struct interface_info *info)
+ struct ifaddrs *ifaddrs;
+ struct ifaddrs *ifa;
+ struct sockaddr_ll *sll = NULL;
++ unsigned char *hw_addr;
+
+ if (getifaddrs(&ifaddrs) == -1)
+ log_fatal("Failed to get interfaces");
+@@ -660,6 +692,10 @@ get_hw_addr(struct interface_info *info)
+
+ hw->hlen = 1;
+ hw->hbuf[0] = HTYPE_INFINIBAND;
++ hw_addr = get_ib_hw_addr(name);
++ if (!hw_addr)
++ log_fatal("Failed getting %s hw addr", name);
++ memcpy (&hw->hbuf [1], hw_addr, 8);
+ break;
+ #if defined(ARPHRD_PPP)
+ case ARPHRD_PPP:
--- /dev/null
+diff -up dhcp-4.2.2/client/dhclient.c.improved-xid dhcp-4.2.2/client/dhclient.c
+--- dhcp-4.2.2/client/dhclient.c.improved-xid 2011-09-16 18:18:00.649730661 +0200
++++ dhcp-4.2.2/client/dhclient.c 2011-09-16 18:22:36.815035513 +0200
+@@ -898,6 +898,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
+@@ -912,14 +932,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);
++ }
++ else
++ srandom(seed + cur_time + (unsigned)getpid());
+
+ /* Setup specific Infiniband options */
+ for (ip = interfaces; ip; ip = ip->next) {
+@@ -1457,7 +1499,7 @@ void dhcpack (packet)
+ return;
+ }
+
+- log_info ("DHCPACK from %s", piaddr (packet -> client_addr));
++ log_info ("DHCPACK from %s (xid=0x%x)", piaddr (packet -> client_addr), client -> xid);
+
+ lease = packet_to_lease (packet, client);
+ if (!lease) {
+@@ -2174,7 +2216,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), client -> xid);
+
+ if (!client -> active) {
+ #if defined (DEBUG)
+@@ -2300,10 +2342,10 @@ void send_discover (cpp)
+ client -> packet.secs = htons (65535);
+ client -> secs = client -> packet.secs;
+
+- 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), client -> xid);
+
+ /* Send out a packet. */
+ result = send_packet (client -> interface, (struct packet *)0,
+@@ -2584,10 +2626,10 @@ void send_request (cpp)
+ client -> packet.secs = htons (65535);
+ }
+
+- log_info ("DHCPREQUEST on %s to %s port %d",
++ log_info ("DHCPREQUEST on %s to %s port %d (xid=0x%x)",
+ client -> name ? client -> name : client -> interface -> name,
+ inet_ntoa (destination.sin_addr),
+- ntohs (destination.sin_port));
++ ntohs (destination.sin_port), client -> xid);
+
+ if (destination.sin_addr.s_addr != INADDR_BROADCAST &&
+ fallback_interface)
+@@ -2618,10 +2660,10 @@ void send_decline (cpp)
+
+ int result;
+
+- log_info ("DHCPDECLINE on %s to %s port %d",
++ log_info ("DHCPDECLINE on %s to %s port %d (xid=0x%x)",
+ client -> name ? client -> name : client -> interface -> name,
+ inet_ntoa (sockaddr_broadcast.sin_addr),
+- ntohs (sockaddr_broadcast.sin_port));
++ ntohs (sockaddr_broadcast.sin_port), client -> xid);
+
+ /* Send out a packet. */
+ result = send_packet (client -> interface, (struct packet *)0,
+@@ -2661,10 +2703,10 @@ void send_release (cpp)
+ return;
+ }
+
+- log_info ("DHCPRELEASE on %s to %s port %d",
++ log_info ("DHCPRELEASE on %s to %s port %d (xid=0x%x)",
+ client -> name ? client -> name : client -> interface -> name,
+ inet_ntoa (destination.sin_addr),
+- ntohs (destination.sin_port));
++ ntohs (destination.sin_port), client -> xid);
+
+ if (fallback_interface)
+ result = send_packet (fallback_interface,
--- /dev/null
+diff -up dhcp-4.2.2/client/dhclient.c.lpf-ib dhcp-4.2.2/client/dhclient.c
+--- dhcp-4.2.2/client/dhclient.c.lpf-ib 2011-09-19 11:24:08.693775799 +0200
++++ dhcp-4.2.2/client/dhclient.c 2011-09-19 11:24:08.703775541 +0200
+@@ -113,6 +113,8 @@ static int check_domain_name_list(const
+ static int check_option_values(struct universe *universe, unsigned int opt,
+ const char *ptr, size_t len);
+
++static void setup_ib_interface(struct interface_info *ip);
++
+ int
+ main(int argc, char **argv) {
+ int fd;
+@@ -919,6 +921,14 @@ 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);
++ }
++ }
++
+ /* Start a configuration state machine for each interface. */
+ #ifdef DHCPv6
+ if (local_family == AF_INET6) {
+@@ -1195,6 +1205,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 -up dhcp-4.2.2/common/bpf.c.lpf-ib dhcp-4.2.2/common/bpf.c
+--- dhcp-4.2.2/common/bpf.c.lpf-ib 2011-09-19 11:24:08.694775773 +0200
++++ dhcp-4.2.2/common/bpf.c 2011-09-19 11:24:08.704775516 +0200
+@@ -198,11 +198,44 @@ struct bpf_insn dhcp_bpf_filter [] = {
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
++/* 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;
+ #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 -up dhcp-4.2.2/common/lpf.c.lpf-ib dhcp-4.2.2/common/lpf.c
+--- dhcp-4.2.2/common/lpf.c.lpf-ib 2011-09-19 11:24:08.694775773 +0200
++++ dhcp-4.2.2/common/lpf.c 2011-09-19 11:26:15.107109935 +0200
+@@ -42,6 +42,7 @@
+ #include "includes/netinet/udp.h"
+ #include "includes/netinet/if_ether.h"
+ #include <net/if.h>
++#include <ifaddrs.h>
+
+ #ifndef PACKET_AUXDATA
+ #define PACKET_AUXDATA 8
+@@ -59,6 +60,15 @@ struct tpacket_auxdata
+ /* Reinitializes the specified interface after an address change. This
+ is not required for packet-filter APIs. */
+
++/* 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
++};
++
+ #ifdef USE_LPF_SEND
+ void if_reinitialize_send (info)
+ struct interface_info *info;
+@@ -86,10 +96,21 @@ int if_register_lpf (info)
+ struct sockaddr common;
+ } sa;
+ struct ifreq ifr;
++ int type;
++ int protocol;
+
+ /* Make an LPF socket. */
+- if ((sock = socket(PF_PACKET, SOCK_RAW,
+- htons((short)ETH_P_ALL))) < 0) {
++ 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;
++ }
++
++ if ((sock = socket(PF_PACKET, type, htons((short)protocol))) < 0) {
+ if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+ errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+ errno == EAFNOSUPPORT || errno == EINVAL) {
+@@ -112,6 +133,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 ||
+@@ -127,8 +149,6 @@ int if_register_lpf (info)
+ log_fatal ("Bind socket to interface: %m");
+ }
+
+- get_hw_addr(info->name, &info->hw_address);
+-
+ return sock;
+ }
+ #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */
+@@ -183,6 +203,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 (HAVE_TR_SUPPORT)
+ extern struct sock_filter dhcp_bpf_tr_filter [];
+@@ -200,11 +222,13 @@ void if_register_receive (info)
+ /* Open a LPF device and hang it on this interface... */
+ info -> rfdesc = if_register_lpf (info);
+
+- 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) {
++ 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 defined (HAVE_TR_SUPPORT)
+@@ -250,15 +274,28 @@ static void lpf_gen_filter_setup (info)
+
+ memset(&p, 0, sizeof(p));
+
+- /* Set up the bpf filter program structure. This is defined in
+- bpf.c */
+- p.len = dhcp_bpf_filter_len;
+- p.filter = dhcp_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_bpf_filter [8].k = ntohs ((short)local_port);
++ if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) {
++ /* Set up the bpf filter program structure. */
++ 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 ((short)local_port);
++ } else {
++ /* Set up the bpf filter program structure.
++ This is defined in bpf.c */
++ p.len = dhcp_bpf_filter_len;
++ p.filter = dhcp_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_bpf_filter [8].k = ntohs ((short)local_port);
++ }
+
+ if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
+ sizeof p) < 0) {
+@@ -315,6 +352,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;
+@@ -335,6 +420,11 @@ ssize_t send_packet (interface, packet,
+ 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;
+
+@@ -356,6 +446,42 @@ ssize_t send_packet (interface, packet,
+ #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;
+@@ -382,6 +508,10 @@ ssize_t receive_packet (interface, buf,
+ };
+ struct cmsghdr *cmsg;
+
++ 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;
+@@ -462,33 +592,44 @@ void maybe_setup_fallback ()
+ }
+
+ void
+-get_hw_addr(const char *name, struct hardware *hw) {
+- int sock;
+- struct ifreq tmp;
+- struct sockaddr *sa;
++get_hw_addr(struct interface_info *info)
++{
++ struct hardware *hw = &info->hw_address;
++ char *name = info->name;
++ struct ifaddrs *ifaddrs;
++ struct ifaddrs *ifa;
++ struct sockaddr_ll *sll = NULL;
+
+- if (strlen(name) >= sizeof(tmp.ifr_name)) {
+- log_fatal("Device name too long: \"%s\"", name);
+- }
++ if (getifaddrs(&ifaddrs) == -1)
++ log_fatal("Failed to get interfaces");
+
+- sock = socket(AF_INET, SOCK_DGRAM, 0);
+- if (sock < 0) {
+- log_fatal("Can't create socket for \"%s\": %m", 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) {
++ sll = (struct sockaddr_ll *)(void *)ifa->ifa_addr;
++ break;
++ }
+ }
+
+- 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",
+- name);
++ if (sll == NULL) {
++ freeifaddrs(ifaddrs);
++ log_fatal("Failed to get HW address for %s\n", name);
+ }
+
+- sa = &tmp.ifr_hwaddr;
+- switch (sa->sa_family) {
++ 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
+@@ -496,18 +637,35 @@ get_hw_addr(const char *name, struct har
+ #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 = 17;
+ hw->hbuf[0] = HTYPE_FDDI;
+- memcpy(&hw->hbuf[1], sa->sa_data, 16);
++ memcpy(&hw->hbuf[1], sll->sll_addr, 16);
++ break;
++ case ARPHRD_INFINIBAND:
++ /* For Infiniband, save the broadcast address and store
++ * the port GUID into the hardware address.
++ */
++ if (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 = 1;
++ hw->hbuf[0] = HTYPE_INFINIBAND;
+ 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("Unsupported device type %ld for \"%s\"",
++ (long int)sll->sll_family, name);
+ hw->hlen = 0;
+ hw->hbuf[0] = HTYPE_RESERVED;
+ /* 0xdeadbeef should never occur on the wire,
+@@ -520,10 +678,11 @@ get_hw_addr(const char *name, struct har
+ break;
+ #endif
+ default:
++ freeifaddrs(ifaddrs);
+ log_fatal("Unsupported device type %ld for \"%s\"",
+- (long int)sa->sa_family, name);
++ (long int)sll->sll_family, name);
+ }
+
+- close(sock);
++ freeifaddrs(ifaddrs);
+ }
+ #endif
+diff -up dhcp-4.2.2/common/socket.c.lpf-ib dhcp-4.2.2/common/socket.c
+--- dhcp-4.2.2/common/socket.c.lpf-ib 2011-06-27 18:18:20.000000000 +0200
++++ dhcp-4.2.2/common/socket.c 2011-09-19 11:24:08.705775490 +0200
+@@ -324,7 +324,7 @@ void if_register_send (info)
+ info->wfdesc = if_register_socket(info, AF_INET, 0);
+ /* 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. */
+@@ -387,7 +387,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",
+@@ -497,7 +497,7 @@ if_register6(struct interface_info *info
+ 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) {
+diff -up dhcp-4.2.2/includes/dhcpd.h.lpf-ib dhcp-4.2.2/includes/dhcpd.h
+--- dhcp-4.2.2/includes/dhcpd.h.lpf-ib 2011-09-19 11:24:08.696775721 +0200
++++ dhcp-4.2.2/includes/dhcpd.h 2011-09-19 11:24:08.707775438 +0200
+@@ -1243,6 +1243,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.
+ */
+@@ -2356,7 +2357,7 @@ void print_dns_status (int, struct dhcp_
+ #endif
+ const char *print_time(TIME);
+
+-void get_hw_addr(const char *name, struct hardware *hw);
++void get_hw_addr(struct interface_info *info);
+
+ /* socket.c */
+ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \
+diff -up dhcp-4.2.2/includes/dhcp.h.lpf-ib dhcp-4.2.2/includes/dhcp.h
+--- dhcp-4.2.2/includes/dhcp.h.lpf-ib 2011-09-19 11:24:08.696775721 +0200
++++ dhcp-4.2.2/includes/dhcp.h 2011-09-19 11:24:08.707775438 +0200
+@@ -79,6 +79,7 @@ struct dhcp_packet {
+ #define HTYPE_ETHER 1 /* Ethernet 10Mbps */
+ #define HTYPE_IEEE802 6 /* IEEE 802.2 Token Ring... */
+ #define HTYPE_FDDI 8 /* FDDI... */
++#define HTYPE_INFINIBAND 32 /* Infiniband IPoIB */
+
+ #define HTYPE_RESERVED 0 /* RFC 5494 */
+
--- /dev/null
+diff -up dhcp-4.2.2b1/client/clparse.c.options dhcp-4.2.2b1/client/clparse.c
+--- dhcp-4.2.2b1/client/clparse.c.options 2011-04-21 16:08:14.000000000 +0200
++++ dhcp-4.2.2b1/client/clparse.c 2011-07-01 13:51:52.935755570 +0200
+@@ -146,6 +146,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)
+@@ -313,7 +314,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;
+@@ -732,6 +734,12 @@ void parse_client_statement (cfile, ip,
+ parse_reject_statement (cfile, config);
+ return;
+
++ case BOOTP_BROADCAST_ALWAYS:
++ token = next_token(&val, (unsigned*)0, cfile);
++ config -> bootp_broadcast_always = 1;
++ parse_semi (cfile);
++ return;
++
+ default:
+ lose = 0;
+ stmt = (struct executable_statement *)0;
+diff -up dhcp-4.2.2b1/client/dhclient.c.options dhcp-4.2.2b1/client/dhclient.c
+--- dhcp-4.2.2b1/client/dhclient.c.options 2011-05-11 16:20:59.000000000 +0200
++++ dhcp-4.2.2b1/client/dhclient.c 2011-07-01 13:51:52.936755545 +0200
+@@ -39,6 +39,12 @@
+ #include <limits.h>
+ #include <dns/result.h>
+
++/*
++ * 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... */
+
+@@ -87,6 +93,9 @@ int wanted_ia_na = -1; /* the absolute
+ int wanted_ia_ta = 0;
+ int wanted_ia_pd = 0;
+ char *mockup_relay = NULL;
++int bootp_broadcast_always = 0;
++
++extern u_int32_t default_requested_options[];
+
+ void run_stateless(int exit_mode);
+
+@@ -123,6 +132,15 @@ main(int argc, char **argv) {
+ int local_family_set = 0;
+ #endif /* DHCPv6 */
+ char *s;
++ 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));
+@@ -310,6 +328,88 @@ main(int argc, char **argv) {
+ } else if (!strcmp(argv[i], "--version")) {
+ log_info("isc-dhclient-%s", PACKAGE_VERSION);
+ exit(0);
++ } else if (!strcmp(argv[i], "-I")) {
++ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++ usage();
++ exit(1);
++ }
++
++ if (strlen(argv[i]) >= DHCP_MAX_OPTION_LEN) {
++ log_error("-I 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();
++ 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 <host-name> and -F <fqdn> 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();
++ 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 <fqdn> argument can be specified");
++ exit(1);
++ }
++
++ if (dhcp_host_name_arg != NULL) {
++ log_error("The -F <fqdn> and -H <host-name> 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();
++ exit(1);
++ }
++
++ if ((timeout_arg = atoi(argv[i])) <= 0) {
++ log_error("-T 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();
++ 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], "-R")) {
++ if ((++i == argc) || (argv[i] == NULL) || (*(argv[i])=='\0')) {
++ usage();
++ exit(1);
++ }
++
++ dhclient_request_options = argv[i];
+ } else if (argv[i][0] == '-') {
+ usage();
+ } else if (interfaces_requested < 0) {
+@@ -484,6 +584,166 @@ 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 -I 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 -R <request options list> 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 -R <request options list> 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 -I/-H/-F/-timeout/-V/-R 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 -I/-H/-F/-timeout/-V/-R configuration arguments", 0);
++
++ if ((status != ISC_R_SUCCESS) || (cfile -> warnings_occurred))
++ log_fatal("Cannot parse -I/-H/-F/-timeout/-V/-R 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 -I/-H/-F/-timeout/-V/-R configuration arguments !");
++ end_parse(&cfile);
++
++ if (timeout_arg) {
++ /* we just set the toplevel timeout, but per-client
++ * timeouts may still be at defaults. Also, it makes no
++ * sense having the reboot_timeout or backoff_cutoff
++ * greater than the timeout:
++ */
++ if ((top_level_config.backoff_cutoff == 15) && (top_level_config.backoff_cutoff > (timeout_arg / 2)))
++ top_level_config.backoff_cutoff = (((unsigned long)(timeout_arg / 2)) == 0) ? timeout_arg : (unsigned long)(timeout_arg / 2);
++
++ for (ip=interfaces; ip; ip = ip->next) {
++ if (ip->client->config->timeout == 60)
++ ip->client->config->timeout = timeout_arg;
++
++ if ((ip->client->config->reboot_timeout == 10) && (ip->client->config->reboot_timeout > ip->client->config->timeout))
++ ip->client->config->reboot_timeout = ip->client->config->timeout;
++ if ((ip->client->config->backoff_cutoff == 15) && (ip->client->config->backoff_cutoff > top_level_config.backoff_cutoff))
++ ip->client->config->backoff_cutoff = top_level_config.backoff_cutoff;
++ }
++ }
++
++ 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();
+
+@@ -2397,7 +2657,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);
+@@ -2481,7 +2742,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);
+@@ -2543,7 +2806,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 -up dhcp-4.2.2b1/common/conflex.c.options dhcp-4.2.2b1/common/conflex.c
+--- dhcp-4.2.2b1/common/conflex.c.options 2011-05-11 16:20:59.000000000 +0200
++++ dhcp-4.2.2b1/common/conflex.c 2011-07-01 13:51:52.938755494 +0200
+@@ -808,6 +808,8 @@ intern(char *atom, enum dhcp_token dfv)
+ return BALANCE;
+ if (!strcasecmp (atom + 1, "ound"))
+ return BOUND;
++ if (!strcasecmp (atom + 1, "ootp-broadcast-always"))
++ return BOOTP_BROADCAST_ALWAYS;
+ break;
+ case 'c':
+ if (!strcasecmp(atom + 1, "ase"))
+diff -up dhcp-4.2.2b1/includes/dhcpd.h.options dhcp-4.2.2b1/includes/dhcpd.h
+--- dhcp-4.2.2b1/includes/dhcpd.h.options 2011-05-20 16:21:11.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhcpd.h 2011-07-01 13:51:52.940755442 +0200
+@@ -1147,6 +1147,9 @@ struct client_config {
+ int do_forward_update; /* If nonzero, and if we have the
+ information we need, update the
+ A record for the address we get. */
++
++ int bootp_broadcast_always; /* If nonzero, always set the BOOTP_BROADCAST
++ flag in requests */
+ };
+
+ /* Per-interface state used in the dhcp client... */
+diff -up dhcp-4.2.2b1/includes/dhctoken.h.options dhcp-4.2.2b1/includes/dhctoken.h
+--- dhcp-4.2.2b1/includes/dhctoken.h.options 2011-05-12 14:02:47.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhctoken.h 2011-07-01 13:53:43.316861637 +0200
+@@ -361,7 +361,8 @@ enum dhcp_token {
+ GETHOSTNAME = 662,
+ REWIND = 663,
+ INITIAL_DELAY = 664,
+- GETHOSTBYNAME = 665
++ GETHOSTBYNAME = 665,
++ BOOTP_BROADCAST_ALWAYS = 666
+ };
+
+ #define is_identifier(x) ((x) >= FIRST_TOKEN && \
--- /dev/null
+diff -up dhcp-4.2.2/client/Makefile.am.rh637017 dhcp-4.2.2/client/Makefile.am
+--- dhcp-4.2.2/client/Makefile.am.rh637017 2010-09-15 00:32:36.000000000 +0200
++++ dhcp-4.2.2/client/Makefile.am 2011-08-11 17:28:58.923897561 +0200
+@@ -5,7 +5,7 @@ dhclient_SOURCES = clparse.c dhclient.c
+ scripts/netbsd scripts/nextstep scripts/openbsd \
+ scripts/solaris scripts/openwrt
+ dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+- ../bind/lib/libdns.a ../bind/lib/libisc.a
++ $(BIND9_LIBDIR) -ldns-export -lisc-export
+ man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
+ EXTRA_DIST = $(man_MANS)
+
+diff -up dhcp-4.2.2/common/tests/Makefile.am.rh637017 dhcp-4.2.2/common/tests/Makefile.am
+--- dhcp-4.2.2/common/tests/Makefile.am.rh637017 2009-10-28 05:12:30.000000000 +0100
++++ dhcp-4.2.2/common/tests/Makefile.am 2011-08-11 17:33:45.258637236 +0200
+@@ -6,6 +6,5 @@ TESTS = test_alloc
+
+ test_alloc_SOURCES = test_alloc.c
+ test_alloc_LDADD = ../libdhcp.a ../../tests/libt_api.a \
+- ../../omapip/libomapi.a ../../bind/lib/libdns.a \
+- ../../bind/lib/libisc.a
+-
++ ../../omapip/libomapi.a \
++ $(BIND9_LIBDIR) -ldns-export -lisc-export
+diff -up dhcp-4.2.2/configure.ac.rh637017 dhcp-4.2.2/configure.ac
+--- dhcp-4.2.2/configure.ac.rh637017 2011-07-20 02:32:18.000000000 +0200
++++ dhcp-4.2.2/configure.ac 2011-08-11 17:28:58.924897535 +0200
+@@ -512,20 +512,37 @@ AC_CHECK_MEMBER(struct msghdr.msg_contro
+ libbind=
+ AC_ARG_WITH(libbind,
+ AC_HELP_STRING([--with-libbind=PATH],
+- [bind includes and libraries are in PATH
+- (default is ./bind)]),
++ [bind includes are in PATH
++ (default is ./bind/includes)]),
+ use_libbind="$withval", use_libbind="no")
+ case "$use_libbind" in
++yes|no)
++ libbind="\${top_srcdir}/bind/include"
++ ;;
++*)
++ libbind="$use_libbind"
++ ;;
++esac
++
++BIND9_LIBDIR='-L$(top_builddir)/bind/lib'
++AC_ARG_WITH(libbind-libs,
++ AC_HELP_STRING([--with-libbind-libs=PATH],
++ [bind9 export libraries are in PATH]),
++ [libbind_libs="$withval"], [libbind_libs='no'])
++case "$libbind_libs" in
+ yes)
+- libbind="\${top_srcdir}/bind"
++ AC_MSG_ERROR([Specify path to bind9 libraries])
+ ;;
+ no)
+- libbind="\${top_srcdir}/bind"
++ BUNDLED_BIND=yes
+ ;;
+ *)
+- libbind="$use_libbind"
++ BIND9_LIBDIR="-L$libbind_libs"
++ BUNDLED_BIND=no
+ ;;
+ esac
++AM_CONDITIONAL([BUNDLED_BIND], [test "$BUNDLED_BIND" = yes])
++AC_SUBST([BIND9_LIBDIR])
+
+ # OpenLDAP support.
+ AC_ARG_WITH(ldap,
+@@ -562,7 +579,7 @@ fi
+ CFLAGS="$CFLAGS $STD_CWARNINGS"
+
+ # Try to add the bind include directory
+-CFLAGS="$CFLAGS -I$libbind/include"
++CFLAGS="$CFLAGS -I$libbind"
+
+ AC_C_FLEXIBLE_ARRAY_MEMBER
+
+diff -up dhcp-4.2.2/dhcpctl/Makefile.am.rh637017 dhcp-4.2.2/dhcpctl/Makefile.am
+--- dhcp-4.2.2/dhcpctl/Makefile.am.rh637017 2009-10-28 05:12:30.000000000 +0100
++++ dhcp-4.2.2/dhcpctl/Makefile.am 2011-08-11 17:28:58.924897535 +0200
+@@ -6,10 +6,10 @@ EXTRA_DIST = $(man_MANS)
+
+ omshell_SOURCES = omshell.c
+ omshell_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
+- ../bind/lib/libdns.a ../bind/lib/libisc.a
++ $(BIND9_LIBDIR) -ldns-export -lisc-export
+
+ libdhcpctl_a_SOURCES = dhcpctl.c callback.c remote.c
+
+ cltest_SOURCES = cltest.c
+ cltest_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
+- ../bind/lib/libdns.a ../bind/lib/libisc.a
+\ No newline at end of file
++ $(BIND9_LIBDIR) -ldns-export -lisc-export
+diff -up dhcp-4.2.2/Makefile.am.rh637017 dhcp-4.2.2/Makefile.am
+--- dhcp-4.2.2/Makefile.am.rh637017 2010-03-25 00:30:38.000000000 +0100
++++ dhcp-4.2.2/Makefile.am 2011-08-11 17:28:58.925897509 +0200
+@@ -21,7 +21,13 @@ EXTRA_DIST = RELNOTES LICENSE \
+ util/bindvar.sh \
+ bind/Makefile bind/bind.tar.gz bind/version.tmp
+
+-SUBDIRS = bind includes tests common dst omapip client dhcpctl relay server
++if BUNDLED_BIND
++SUBDIRS = bind
++else
++SUBDIRS =
++endif
++
++SUBDIRS += includes tests common dst omapip client dhcpctl relay server
+
+ nobase_include_HEADERS = dhcpctl/dhcpctl.h
+
+diff -up dhcp-4.2.2/omapip/Makefile.am.rh637017 dhcp-4.2.2/omapip/Makefile.am
+--- dhcp-4.2.2/omapip/Makefile.am.rh637017 2010-02-12 01:13:54.000000000 +0100
++++ dhcp-4.2.2/omapip/Makefile.am 2011-08-11 17:28:58.939897149 +0200
+@@ -10,5 +10,5 @@ man_MANS = omapi.3
+ EXTRA_DIST = $(man_MANS)
+
+ svtest_SOURCES = test.c
+-svtest_LDADD = libomapi.a ../bind/lib/libdns.a ../bind/lib/libisc.a
++svtest_LDADD = libomapi.a $(BIND9_LIBDIR) -ldns-export -lisc-export
+
+diff -up dhcp-4.2.2/relay/Makefile.am.rh637017 dhcp-4.2.2/relay/Makefile.am
+--- dhcp-4.2.2/relay/Makefile.am.rh637017 2009-10-28 05:12:30.000000000 +0100
++++ dhcp-4.2.2/relay/Makefile.am 2011-08-11 17:28:58.940897123 +0200
+@@ -3,7 +3,7 @@ AM_CPPFLAGS = -DLOCALSTATEDIR='"@localst
+ sbin_PROGRAMS = dhcrelay
+ dhcrelay_SOURCES = dhcrelay.c
+ dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+- ../bind/lib/libdns.a ../bind/lib/libisc.a
++ $(BIND9_LIBDIR) -ldns-export -lisc-export
+ man_MANS = dhcrelay.8
+ EXTRA_DIST = $(man_MANS)
+
+diff -up dhcp-4.2.2/server/Makefile.am.rh637017 dhcp-4.2.2/server/Makefile.am
+--- dhcp-4.2.2/server/Makefile.am.rh637017 2010-03-24 22:49:47.000000000 +0100
++++ dhcp-4.2.2/server/Makefile.am 2011-08-11 17:28:58.944897021 +0200
+@@ -8,8 +8,7 @@ dhcpd_SOURCES = dhcpd.c dhcp.c bootp.c c
+
+ dhcpd_CFLAGS = $(LDAP_CFLAGS)
+ dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+- ../dhcpctl/libdhcpctl.a ../bind/lib/libdns.a \
+- ../bind/lib/libisc.a
++ ../dhcpctl/libdhcpctl.a $(BIND9_LIBDIR) -ldns-export -lisc-export
+
+ man_MANS = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
+ EXTRA_DIST = $(man_MANS)
--- /dev/null
+diff -up dhcp-4.2.2b1/client/clparse.c.rfc3442 dhcp-4.2.2b1/client/clparse.c
+--- dhcp-4.2.2b1/client/clparse.c.rfc3442 2011-07-01 14:22:38.031534508 +0200
++++ dhcp-4.2.2b1/client/clparse.c 2011-07-01 14:22:38.128532940 +0200
+@@ -37,7 +37,7 @@
+
+ struct client_config top_level_config;
+
+-#define NUM_DEFAULT_REQUESTED_OPTS 14
++#define NUM_DEFAULT_REQUESTED_OPTS 15
+ struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
+
+ static void parse_client_default_duid(struct parse *cfile);
+@@ -82,7 +82,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);
+
+@@ -136,6 +140,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 -up dhcp-4.2.2b1/common/dhcp-options.5.rfc3442 dhcp-4.2.2b1/common/dhcp-options.5
+--- dhcp-4.2.2b1/common/dhcp-options.5.rfc3442 2011-07-01 14:22:38.020534686 +0200
++++ dhcp-4.2.2b1/common/dhcp-options.5 2011-07-01 14:22:38.129532924 +0200
+@@ -115,6 +115,26 @@ hexadecimal, separated by colons. For
+ 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
+@@ -931,6 +951,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 -up dhcp-4.2.2b1/common/inet.c.rfc3442 dhcp-4.2.2b1/common/inet.c
+--- dhcp-4.2.2b1/common/inet.c.rfc3442 2011-05-11 02:47:22.000000000 +0200
++++ dhcp-4.2.2b1/common/inet.c 2011-07-01 14:22:38.130532908 +0200
+@@ -528,6 +528,60 @@ free_iaddrcidrnetlist(struct iaddrcidrne
+ 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 "<null destination descriptor>";
++ }
++ 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 -up dhcp-4.2.2b1/common/options.c.rfc3442 dhcp-4.2.2b1/common/options.c
+--- dhcp-4.2.2b1/common/options.c.rfc3442 2011-03-24 22:57:13.000000000 +0100
++++ dhcp-4.2.2b1/common/options.c 2011-07-01 14:22:38.132532876 +0200
+@@ -706,7 +706,11 @@ cons_options(struct packet *inpacket, st
+ * 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;
+@@ -1683,6 +1687,7 @@ const char *pretty_print_option (option,
+ const unsigned char *dp = data;
+ char comma;
+ unsigned long tval;
++ unsigned int octets = 0;
+
+ if (emit_commas)
+ comma = ',';
+@@ -1691,6 +1696,7 @@ const char *pretty_print_option (option,
+
+ 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)
+@@ -1840,6 +1846,33 @@ const char *pretty_print_option (option,
+ 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++) {
+ for (j = 0; j < numelem; j++) {
+@@ -1978,6 +2011,20 @@ const char *pretty_print_option (option,
+ 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 "<error>";
++ }
++
++ 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 -up dhcp-4.2.2b1/common/parse.c.rfc3442 dhcp-4.2.2b1/common/parse.c
+--- dhcp-4.2.2b1/common/parse.c.rfc3442 2011-07-01 14:22:38.097533441 +0200
++++ dhcp-4.2.2b1/common/parse.c 2011-07-01 14:22:38.135532828 +0200
+@@ -341,6 +341,39 @@ int parse_ip_addr (cfile, addr)
+ }
+
+ /*
++ * 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.
+ */
+ static int
+@@ -700,8 +733,10 @@ unsigned char *parse_numeric_aggregate (
+ 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,
+@@ -1624,6 +1659,9 @@ int parse_option_code_definition (cfile,
+ case IP_ADDRESS:
+ type = 'I';
+ break;
++ case DESTINATION_DESCRIPTOR:
++ type = 'R';
++ break;
+ case IP6_ADDRESS:
+ type = '6';
+ break;
+@@ -5288,6 +5326,15 @@ int parse_option_token (rv, cfile, fmt,
+ }
+ 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;
+@@ -5548,6 +5595,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 -up dhcp-4.2.2b1/common/tables.c.rfc3442 dhcp-4.2.2b1/common/tables.c
+--- dhcp-4.2.2b1/common/tables.c.rfc3442 2011-07-01 14:22:38.087533601 +0200
++++ dhcp-4.2.2b1/common/tables.c 2011-07-01 14:22:38.137532796 +0200
+@@ -51,6 +51,7 @@ HASH_FUNCTIONS (option_code, const unsig
+ Format codes:
+
+ I - IPv4 address
++ R - destination descriptor (RFC3442)
+ 6 - IPv6 address
+ l - 32-bit signed integer
+ L - 32-bit unsigned integer
+@@ -208,6 +209,7 @@ static struct option dhcp_options[] = {
+ { "default-url", "t", &dhcp_universe, 114, 1 },
+ { "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 -up dhcp-4.2.2b1/includes/dhcpd.h.rfc3442 dhcp-4.2.2b1/includes/dhcpd.h
+--- dhcp-4.2.2b1/includes/dhcpd.h.rfc3442 2011-07-01 14:22:38.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhcpd.h 2011-07-01 14:24:19.999810333 +0200
+@@ -2662,6 +2662,7 @@ isc_result_t range2cidr(struct iaddrcidr
+ 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 *);
+@@ -2869,6 +2870,7 @@ void parse_client_lease_declaration (str
+ 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 -up dhcp-4.2.2b1/includes/dhcp.h.rfc3442 dhcp-4.2.2b1/includes/dhcp.h
+--- dhcp-4.2.2b1/includes/dhcp.h.rfc3442 2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/includes/dhcp.h 2011-07-01 14:22:38.145532665 +0200
+@@ -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 -up dhcp-4.2.2b1/includes/dhctoken.h.rfc3442 dhcp-4.2.2b1/includes/dhctoken.h
+--- dhcp-4.2.2b1/includes/dhctoken.h.rfc3442 2011-07-01 14:22:37.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhctoken.h 2011-07-01 14:25:12.541867623 +0200
+@@ -362,7 +362,8 @@ enum dhcp_token {
+ REWIND = 663,
+ INITIAL_DELAY = 664,
+ GETHOSTBYNAME = 665,
+- BOOTP_BROADCAST_ALWAYS = 666
++ BOOTP_BROADCAST_ALWAYS = 666,
++ DESTINATION_DESCRIPTOR = 667
+ };
+
+ #define is_identifier(x) ((x) >= FIRST_TOKEN && \
--- /dev/null
+diff -up dhcp-4.2.2/client/Makefile.am.sharedlib dhcp-4.2.2/client/Makefile.am
+--- dhcp-4.2.2/client/Makefile.am.sharedlib 2011-09-09 16:35:56.000000000 +0200
++++ dhcp-4.2.2/client/Makefile.am 2011-09-09 16:36:29.849007951 +0200
+@@ -4,7 +4,7 @@ dhclient_SOURCES = clparse.c dhclient.c
+ scripts/bsdos scripts/freebsd scripts/linux scripts/macos \
+ scripts/netbsd scripts/nextstep scripts/openbsd \
+ scripts/solaris scripts/openwrt
+-dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
++dhclient_LDADD = ../common/libdhcp.a ../omapip/libomapi.la \
+ $(BIND9_LIBDIR) -ldns-export -lisc-export $(CAPNG_LDADD)
+ man_MANS = dhclient.8 dhclient-script.8 dhclient.conf.5 dhclient.leases.5
+ EXTRA_DIST = $(man_MANS)
+diff -up dhcp-4.2.2/configure.ac.sharedlib dhcp-4.2.2/configure.ac
+--- dhcp-4.2.2/configure.ac.sharedlib 2011-09-09 16:35:56.097000001 +0200
++++ dhcp-4.2.2/configure.ac 2011-09-09 16:35:56.383000000 +0200
+@@ -30,7 +30,8 @@ fi
+ # Use this to define _GNU_SOURCE to pull in the IPv6 Advanced Socket API.
+ AC_USE_SYSTEM_EXTENSIONS
+
+-AC_PROG_RANLIB
++# Use libtool to simplify building of shared libraries
++AC_PROG_LIBTOOL
+ AC_CONFIG_HEADERS([includes/config.h])
+
+ # we sometimes need to know byte order for building packets
+diff -up dhcp-4.2.2/dhcpctl/Makefile.am.sharedlib dhcp-4.2.2/dhcpctl/Makefile.am
+--- dhcp-4.2.2/dhcpctl/Makefile.am.sharedlib 2011-09-09 16:35:55.459000001 +0200
++++ dhcp-4.2.2/dhcpctl/Makefile.am 2011-09-09 16:35:56.384000000 +0200
+@@ -1,15 +1,15 @@
+ bin_PROGRAMS = omshell
+-lib_LIBRARIES = libdhcpctl.a
++lib_LTLIBRARIES = libdhcpctl.la
+ noinst_PROGRAMS = cltest
+ man_MANS = omshell.1 dhcpctl.3
+ EXTRA_DIST = $(man_MANS)
+
+ omshell_SOURCES = omshell.c
+-omshell_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
++omshell_LDADD = libdhcpctl.la ../common/libdhcp.a ../omapip/libomapi.la \
+ $(BIND9_LIBDIR) -ldns-export -lisc-export
+
+-libdhcpctl_a_SOURCES = dhcpctl.c callback.c remote.c
++libdhcpctl_la_SOURCES = dhcpctl.c callback.c remote.c
+
+ cltest_SOURCES = cltest.c
+-cltest_LDADD = libdhcpctl.a ../common/libdhcp.a ../omapip/libomapi.a \
++cltest_LDADD = libdhcpctl.la ../common/libdhcp.a ../omapip/libomapi.la \
+ $(BIND9_LIBDIR) -ldns-export -lisc-export
+diff -up dhcp-4.2.2/dst/base64.c.sharedlib dhcp-4.2.2/dst/base64.c
+--- dhcp-4.2.2/dst/base64.c.sharedlib 2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2/dst/base64.c 2011-09-09 16:35:56.385000000 +0200
+@@ -64,6 +64,7 @@ static const char rcsid[] = "$Id: base64
+
+ #include <sys/socket.h>
+
++#include "dst_internal.h"
+ #include "cdefs.h"
+ #include "osdep.h"
+ #include "arpa/nameser.h"
+diff -up dhcp-4.2.2/dst/Makefile.am.sharedlib dhcp-4.2.2/dst/Makefile.am
+--- dhcp-4.2.2/dst/Makefile.am.sharedlib 2007-05-29 18:32:10.000000000 +0200
++++ dhcp-4.2.2/dst/Makefile.am 2011-09-09 16:35:56.386000000 +0200
+@@ -1,8 +1,8 @@
+ AM_CPPFLAGS = -DMINIRES_LIB -DHMAC_MD5
+
+-lib_LIBRARIES = libdst.a
++lib_LTLIBRARIES = libdst.la
+
+-libdst_a_SOURCES = dst_support.c dst_api.c hmac_link.c md5_dgst.c \
++libdst_la_SOURCES = dst_support.c dst_api.c hmac_link.c md5_dgst.c \
+ base64.c prandom.c
+
+ EXTRA_DIST = dst_internal.h md5.h md5_locl.h
+diff -up dhcp-4.2.2/omapip/Makefile.am.sharedlib dhcp-4.2.2/omapip/Makefile.am
+--- dhcp-4.2.2/omapip/Makefile.am.sharedlib 2011-09-09 16:35:55.000000000 +0200
++++ dhcp-4.2.2/omapip/Makefile.am 2011-09-09 16:37:36.734000324 +0200
+@@ -1,7 +1,7 @@
+-lib_LIBRARIES = libomapi.a
++lib_LTLIBRARIES = libomapi.la
+ noinst_PROGRAMS = svtest
+
+-libomapi_a_SOURCES = protocol.c buffer.c alloc.c result.c connection.c \
++libomapi_la_SOURCES = protocol.c buffer.c alloc.c result.c connection.c \
+ errwarn.c listener.c dispatch.c generic.c support.c \
+ handle.c message.c convert.c hash.c auth.c inet_addr.c \
+ array.c trace.c toisc.c iscprint.c isclib.c
+@@ -10,5 +10,5 @@ man_MANS = omapi.3
+ EXTRA_DIST = $(man_MANS)
+
+ svtest_SOURCES = test.c
+-svtest_LDADD = libomapi.a $(BIND9_LIBDIR) -ldns-export -lisc-export
++svtest_LDADD = libomapi.la $(BIND9_LIBDIR) -ldns-export -lisc-export
+
+diff -up dhcp-4.2.2/relay/Makefile.am.sharedlib dhcp-4.2.2/relay/Makefile.am
+--- dhcp-4.2.2/relay/Makefile.am.sharedlib 2011-09-09 16:35:56.000000000 +0200
++++ dhcp-4.2.2/relay/Makefile.am 2011-09-09 16:37:57.058019749 +0200
+@@ -2,7 +2,7 @@ AM_CPPFLAGS = -DLOCALSTATEDIR='"@localst
+
+ sbin_PROGRAMS = dhcrelay
+ dhcrelay_SOURCES = dhcrelay.c
+-dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
++dhcrelay_LDADD = ../common/libdhcp.a ../omapip/libomapi.la \
+ $(BIND9_LIBDIR) -ldns-export -lisc-export $(CAPNG_LDADD)
+ man_MANS = dhcrelay.8
+ EXTRA_DIST = $(man_MANS)
+diff -up dhcp-4.2.2/server/Makefile.am.sharedlib dhcp-4.2.2/server/Makefile.am
+--- dhcp-4.2.2/server/Makefile.am.sharedlib 2011-09-09 16:35:56.000000000 +0200
++++ dhcp-4.2.2/server/Makefile.am 2011-09-09 16:38:56.291004599 +0200
+@@ -7,8 +7,8 @@ dhcpd_SOURCES = dhcpd.c dhcp.c bootp.c c
+ dhcpv6.c mdb6.c ldap.c ldap_casa.c
+
+ dhcpd_CFLAGS = $(LDAP_CFLAGS)
+-dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.a \
+- ../dhcpctl/libdhcpctl.a $(BIND9_LIBDIR) -ldns-export -lisc-export \
++dhcpd_LDADD = ../common/libdhcp.a ../omapip/libomapi.la \
++ ../dhcpctl/libdhcpctl.la $(BIND9_LIBDIR) -ldns-export -lisc-export \
+ $(CAPNG_LDADD)
+
+ man_MANS = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
--- /dev/null
+diff -up dhcp-4.2.2b1/common/bpf.c.xen dhcp-4.2.2b1/common/bpf.c
+--- dhcp-4.2.2b1/common/bpf.c.xen 2009-11-20 02:48:59.000000000 +0100
++++ dhcp-4.2.2b1/common/bpf.c 2011-07-01 14:00:16.936959001 +0200
+@@ -485,7 +485,7 @@ ssize_t receive_packet (interface, buf,
+ offset = decode_udp_ip_header (interface,
+ interface -> rbuf,
+ interface -> rbuf_offset,
+- from, hdr.bh_caplen, &paylen);
++ from, hdr.bh_caplen, &paylen, 0);
+
+ /* If the IP or UDP checksum was bad, skip the packet... */
+ if (offset < 0) {
+diff -up dhcp-4.2.2b1/common/dlpi.c.xen dhcp-4.2.2b1/common/dlpi.c
+--- dhcp-4.2.2b1/common/dlpi.c.xen 2011-05-11 16:20:59.000000000 +0200
++++ dhcp-4.2.2b1/common/dlpi.c 2011-07-01 14:00:16.937958997 +0200
+@@ -693,7 +693,7 @@ ssize_t receive_packet (interface, buf,
+ length -= offset;
+ #endif
+ offset = decode_udp_ip_header (interface, dbuf, bufix,
+- from, length, &paylen);
++ from, length, &paylen, 0);
+
+ /*
+ * If the IP or UDP checksum was bad, skip the packet...
+diff -up dhcp-4.2.2b1/common/lpf.c.xen dhcp-4.2.2b1/common/lpf.c
+--- dhcp-4.2.2b1/common/lpf.c.xen 2011-05-10 16:38:58.000000000 +0200
++++ dhcp-4.2.2b1/common/lpf.c 2011-07-01 14:11:24.725748028 +0200
+@@ -29,19 +29,33 @@
+ #include "dhcpd.h"
+ #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE)
+ #include <sys/ioctl.h>
++#include <sys/socket.h>
+ #include <sys/uio.h>
+ #include <errno.h>
+
+ #include <asm/types.h>
+ #include <linux/filter.h>
+ #include <linux/if_ether.h>
++#include <linux/if_packet.h>
+ #include <netinet/in_systm.h>
+-#include <net/if_packet.h>
+ #include "includes/netinet/ip.h"
+ #include "includes/netinet/udp.h"
+ #include "includes/netinet/if_ether.h"
+ #include <net/if.h>
+
++#ifndef PACKET_AUXDATA
++#define PACKET_AUXDATA 8
++
++struct tpacket_auxdata
++{
++ __u32 tp_status;
++ __u32 tp_len;
++ __u32 tp_snaplen;
++ __u16 tp_mac;
++ __u16 tp_net;
++};
++#endif
++
+ /* Reinitializes the specified interface after an address change. This
+ is not required for packet-filter APIs. */
+
+@@ -67,10 +81,14 @@ int if_register_lpf (info)
+ struct interface_info *info;
+ {
+ int sock;
+- struct sockaddr sa;
++ union {
++ struct sockaddr_ll ll;
++ struct sockaddr common;
++ } sa;
++ struct ifreq ifr;
+
+ /* Make an LPF socket. */
+- if ((sock = socket(PF_PACKET, SOCK_PACKET,
++ if ((sock = socket(PF_PACKET, SOCK_RAW,
+ htons((short)ETH_P_ALL))) < 0) {
+ if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+ errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+@@ -85,11 +103,17 @@ int if_register_lpf (info)
+ log_fatal ("Open a socket for LPF: %m");
+ }
+
++ memset (&ifr, 0, sizeof ifr);
++ strncpy (ifr.ifr_name, (const char *)info -> ifp, sizeof ifr.ifr_name);
++ ifr.ifr_name[IFNAMSIZ-1] = '\0';
++ if (ioctl (sock, SIOCGIFINDEX, &ifr))
++ log_fatal ("Failed to get interface index: %m");
++
+ /* Bind to the interface name */
+ memset (&sa, 0, sizeof sa);
+- sa.sa_family = AF_PACKET;
+- strncpy (sa.sa_data, (const char *)info -> ifp, sizeof sa.sa_data);
+- if (bind (sock, &sa, sizeof sa)) {
++ sa.ll.sll_family = AF_PACKET;
++ sa.ll.sll_ifindex = ifr.ifr_ifindex;
++ if (bind (sock, &sa.common, sizeof sa)) {
+ if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT ||
+ errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT ||
+ errno == EAFNOSUPPORT || errno == EINVAL) {
+@@ -171,9 +195,18 @@ static void lpf_gen_filter_setup (struct
+ void if_register_receive (info)
+ struct interface_info *info;
+ {
++ int val;
++
+ /* Open a LPF device and hang it on this interface... */
+ info -> rfdesc = if_register_lpf (info);
+
++ 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 defined (HAVE_TR_SUPPORT)
+ if (info -> hw_address.hbuf [0] == HTYPE_IEEE802)
+ lpf_tr_filter_setup (info);
+@@ -295,7 +328,6 @@ ssize_t send_packet (interface, packet,
+ double hh [16];
+ double ih [1536 / sizeof (double)];
+ unsigned char *buf = (unsigned char *)ih;
+- struct sockaddr_pkt sa;
+ int result;
+ int fudge;
+
+@@ -316,17 +348,7 @@ ssize_t send_packet (interface, packet,
+ (unsigned char *)raw, len);
+ memcpy (buf + ibufp, raw, len);
+
+- /* For some reason, SOCK_PACKET sockets can't be connected,
+- so we have to do a sentdo every time. */
+- memset (&sa, 0, sizeof sa);
+- sa.spkt_family = AF_PACKET;
+- strncpy ((char *)sa.spkt_device,
+- (const char *)interface -> ifp, sizeof sa.spkt_device);
+- sa.spkt_protocol = htons(ETH_P_IP);
+-
+- result = sendto (interface -> wfdesc,
+- buf + fudge, ibufp + len - fudge, 0,
+- (const struct sockaddr *)&sa, sizeof sa);
++ result = write (interface -> wfdesc, buf + fudge, ibufp + len - fudge);
+ if (result < 0)
+ log_error ("send_packet: %m");
+ return result;
+@@ -343,14 +365,35 @@ ssize_t receive_packet (interface, buf,
+ {
+ int length = 0;
+ int offset = 0;
++ int nocsum = 0;
+ unsigned char ibuf [1536];
+ unsigned bufix = 0;
+ unsigned paylen;
++ unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
++ struct iovec iov = {
++ .iov_base = ibuf,
++ .iov_len = sizeof ibuf,
++ };
++ struct msghdr msg = {
++ .msg_iov = &iov,
++ .msg_iovlen = 1,
++ .msg_control = cmsgbuf,
++ .msg_controllen = sizeof(cmsgbuf),
++ };
++ struct cmsghdr *cmsg;
+
+- length = read (interface -> rfdesc, ibuf, sizeof ibuf);
++ length = recvmsg (interface -> rfdesc, &msg, 0);
+ if (length <= 0)
+ return length;
+
++ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
++ if (cmsg->cmsg_level == SOL_PACKET &&
++ cmsg->cmsg_type == PACKET_AUXDATA) {
++ struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
++ nocsum = aux->tp_status & TP_STATUS_CSUMNOTREADY;
++ }
++ }
++
+ bufix = 0;
+ /* Decode the physical header... */
+ offset = decode_hw_header (interface, ibuf, bufix, hfrom);
+@@ -367,7 +410,7 @@ ssize_t receive_packet (interface, buf,
+
+ /* Decode the IP and UDP headers... */
+ offset = decode_udp_ip_header (interface, ibuf, bufix, from,
+- (unsigned)length, &paylen);
++ (unsigned)length, &paylen, nocsum);
+
+ /* If the IP or UDP checksum was bad, skip the packet... */
+ if (offset < 0)
+diff -up dhcp-4.2.2b1/common/nit.c.xen dhcp-4.2.2b1/common/nit.c
+--- dhcp-4.2.2b1/common/nit.c.xen 2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/common/nit.c 2011-07-01 14:00:16.939958989 +0200
+@@ -369,7 +369,7 @@ ssize_t receive_packet (interface, buf,
+
+ /* Decode the IP and UDP headers... */
+ offset = decode_udp_ip_header (interface, ibuf, bufix,
+- from, length, &paylen);
++ from, length, &paylen, 0);
+
+ /* If the IP or UDP checksum was bad, skip the packet... */
+ if (offset < 0)
+diff -up dhcp-4.2.2b1/common/packet.c.xen dhcp-4.2.2b1/common/packet.c
+--- dhcp-4.2.2b1/common/packet.c.xen 2009-07-23 20:52:20.000000000 +0200
++++ dhcp-4.2.2b1/common/packet.c 2011-07-01 14:00:16.939958989 +0200
+@@ -211,7 +211,7 @@ ssize_t
+ decode_udp_ip_header(struct interface_info *interface,
+ unsigned char *buf, unsigned bufix,
+ struct sockaddr_in *from, unsigned buflen,
+- unsigned *rbuflen)
++ unsigned *rbuflen, int nocsum)
+ {
+ unsigned char *data;
+ struct ip ip;
+@@ -322,7 +322,7 @@ decode_udp_ip_header(struct interface_in
+ 8, IPPROTO_UDP + ulen))));
+
+ udp_packets_seen++;
+- if (usum && usum != sum) {
++ if (!nocsum && usum && usum != sum) {
+ udp_packets_bad_checksum++;
+ if (udp_packets_seen > 4 &&
+ (udp_packets_seen / udp_packets_bad_checksum) < 2) {
+diff -up dhcp-4.2.2b1/common/upf.c.xen dhcp-4.2.2b1/common/upf.c
+--- dhcp-4.2.2b1/common/upf.c.xen 2009-11-20 02:49:01.000000000 +0100
++++ dhcp-4.2.2b1/common/upf.c 2011-07-01 14:00:16.940958986 +0200
+@@ -320,7 +320,7 @@ ssize_t receive_packet (interface, buf,
+
+ /* Decode the IP and UDP headers... */
+ offset = decode_udp_ip_header (interface, ibuf, bufix,
+- from, length, &paylen);
++ from, length, &paylen, 0);
+
+ /* If the IP or UDP checksum was bad, skip the packet... */
+ if (offset < 0)
+diff -up dhcp-4.2.2b1/includes/dhcpd.h.xen dhcp-4.2.2b1/includes/dhcpd.h
+--- dhcp-4.2.2b1/includes/dhcpd.h.xen 2011-07-01 14:00:16.000000000 +0200
++++ dhcp-4.2.2b1/includes/dhcpd.h 2011-07-01 14:12:18.069642470 +0200
+@@ -2796,7 +2796,7 @@ ssize_t decode_hw_header (struct interfa
+ unsigned, struct hardware *);
+ ssize_t decode_udp_ip_header (struct interface_info *, unsigned char *,
+ unsigned, struct sockaddr_in *,
+- unsigned, unsigned *);
++ unsigned, unsigned *, int);
+
+ /* ethernet.c */
+ void assemble_ethernet_header (struct interface_info *, unsigned char *,
--- /dev/null
+diff -uNr netkit-telnet-0.17/telnetd/telnetd.c netkit-telnet-0.17.ipv6/telnetd/telnetd.c\r
+--- netkit-telnet-0.17/telnetd/telnetd.c 2006-07-13 08:37:18.000000000 +0200\r
++++ netkit-telnet-0.17.ipv6/telnetd/telnetd.c 2006-07-14 08:36:11.000000000 +0200\r
+@@ -49,6 +49,7 @@\r
+ /* #include <netinet/ip.h> */ /* Don't think this is used at all here */\r
+ #include <arpa/inet.h>\r
+ #include <assert.h>\r
++#include <sys/poll.h>\r
+ #include "telnetd.h"\r
+ #include "pathnames.h"\r
+ #include "setproctitle.h"\r
+@@ -68,7 +69,7 @@\r
+ #define HAS_IPPROTO_IP\r
+ #endif\r
+ \r
+-static void doit(struct sockaddr_in *who);\r
++static void doit(struct sockaddr *who, socklen_t wholen);\r
+ static int terminaltypeok(const char *s);\r
+ \r
+ /*\r
+@@ -90,7 +91,7 @@\r
+ int\r
+ main(int argc, char *argv[], char *env[])\r
+ {\r
+- struct sockaddr_in from;\r
++ struct sockaddr from;\r
+ int on = 1;\r
+ socklen_t fromlen;\r
+ register int ch;\r
+@@ -248,64 +249,89 @@\r
+ argc -= optind;\r
+ argv += optind;\r
+ \r
+- if (debug) {\r
+- int s, ns;\r
+- socklen_t foo;\r
+- struct servent *sp;\r
+- struct sockaddr_in sn;\r
++ int s = 0;\r
+ \r
+- memset(&sn, 0, sizeof(sn));\r
+- sn.sin_family = AF_INET;\r
++ if (debug) {\r
++ struct addrinfo *ai;\r
++ unsigned int nfds = 0;\r
++ struct pollfd fds[2];\r
+ \r
+ if (argc > 1) {\r
+- usage();\r
+- /* NOTREACHED */\r
+- } else if (argc == 1) {\r
+- if ((sp = getservbyname(*argv, "tcp"))!=NULL) {\r
+- sn.sin_port = sp->s_port;\r
+- } \r
+- else {\r
+- int pt = atoi(*argv);\r
+- if (pt <= 0) {\r
+- fprintf(stderr, "telnetd: %s: bad port number\n",\r
+- *argv);\r
+- usage();\r
+- /* NOTREACHED */\r
+- }\r
+- sn.sin_port = htons(pt);\r
+- }\r
++ usage();\r
++ /* NOTREACHED */\r
+ } else {\r
+- sp = getservbyname("telnet", "tcp");\r
+- if (sp == 0) {\r
+- fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");\r
+- exit(1);\r
+- }\r
+- sn.sin_port = sp->s_port;\r
+- }\r
++ struct addrinfo hints;\r
++\r
++ memset (&hints, '\0', sizeof (hints));\r
++ hints.ai_socktype = SOCK_STREAM;\r
++ hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;\r
++ hints.ai_protocol = IPPROTO_TCP;\r
++\r
++ if (argc == 0) {\r
++ if (getaddrinfo(NULL, "telnet", &hints, &ai) != 0) {\r
++ fprintf(stderr, "telnetd: %s: bad port number\n", *argv);\r
++ usage();\r
++ /* NOTREACHED */\r
++ }\r
++ } else {\r
++ if (getaddrinfo(NULL, *argv, &hints, &ai) != 0) {\r
++ fprintf(stderr, "telnetd: %s: bad port number\n", *argv);\r
++ usage();\r
++ /* NOTREACHED */\r
++ }\r
++ }\r
++ } \r
+ \r
+- s = socket(AF_INET, SOCK_STREAM, 0);\r
+- if (s < 0) {\r
++ struct addrinfo *runp;\r
++ int b = 0;\r
++ for (runp = ai; ((runp != NULL) && (nfds < sizeof (fds) / sizeof (fds[0]))); runp = runp->ai_next) {\r
++ fds[nfds].fd = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);\r
++ if (fds[nfds].fd < 0) {\r
+ perror("telnetd: socket");;\r
+- exit(1);\r
++ exit(1);\r
++ }\r
++ fds[nfds].events = POLLIN;\r
++ (void) setsockopt(fds[nfds].fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));\r
++\r
++ if (bind(fds[nfds].fd, runp->ai_addr, runp->ai_addrlen) != 0) {\r
++ // Unable to bind to given port. One of the reason can be\r
++ // that we can't bind to both IPv4 and IPv6\r
++ break;\r
++ } else { \r
++ b++;\r
++ }\r
++\r
++ if (listen(fds[nfds].fd, 1) < 0) {\r
++ perror("listen");\r
++ exit(1);\r
++ }\r
++ nfds++;\r
+ }\r
+- (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));\r
+- if (bind(s, (struct sockaddr *)&sn, sizeof(sn)) < 0) {\r
+- perror("bind");\r
+- exit(1);\r
+- }\r
+- if (listen(s, 1) < 0) {\r
+- perror("listen");\r
+- exit(1);\r
++ freeaddrinfo(ai);\r
++\r
++ if (b == 0) {\r
++ perror("bind");\r
++ exit(1);\r
+ }\r
+- foo = sizeof(sn);\r
+- ns = accept(s, (struct sockaddr *)&sn, &foo);\r
+- if (ns < 0) {\r
+- perror("accept");\r
+- exit(1);\r
++\r
++ int n = poll (fds, nfds, -1);\r
++ if (n > 0) {\r
++ unsigned int i;\r
++ for (i = 0; i < nfds; i++) {\r
++ if (fds[i].revents & POLLIN) {\r
++ struct sockaddr_storage rem;\r
++ socklen_t remlen = sizeof(rem);\r
++ int fd = accept(fds[i].fd, (struct sockaddr *) &rem, &remlen);\r
++\r
++ if (fd < 0) {\r
++ perror("accept");\r
++ exit(1);\r
++ }\r
++\r
++ s = fd;\r
++ }\r
++ }\r
+ }\r
+- (void) dup2(ns, 0);\r
+- (void) close(ns);\r
+- (void) close(s);\r
+ } else if (argc > 0) {\r
+ usage();\r
+ /* NOT REACHED */\r
+@@ -313,13 +339,13 @@\r
+ \r
+ openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);\r
+ fromlen = sizeof (from);\r
+- if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {\r
++ if (getpeername(s, &from, &fromlen) < 0) {\r
+ fprintf(stderr, "%s: ", progname);\r
+ perror("getpeername");\r
+ _exit(1);\r
+ }\r
+ if (keepalive &&\r
+- setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {\r
++ setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {\r
+ syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");\r
+ }\r
+ \r
+@@ -333,13 +359,13 @@\r
+ if (tos < 0)\r
+ tos = 020; /* Low Delay bit */\r
+ if (tos\r
+- && (setsockopt(0, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)\r
++ && (setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)\r
+ && (errno != ENOPROTOOPT) )\r
+ syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");\r
+ }\r
+ #endif /* defined(HAS_IPPROTO_IP) && defined(IP_TOS) */\r
+- net = 0;\r
+- doit(&from);\r
++ net = s;\r
++ doit(&from, fromlen);\r
+ /* NOTREACHED */\r
+ return 0;\r
+ } /* end of main */\r
+@@ -608,10 +634,9 @@\r
+ * Get a pty, scan input lines.\r
+ */\r
+ static void\r
+-doit(struct sockaddr_in *who)\r
++doit(struct sockaddr *who, socklen_t wholen)\r
+ {\r
+ const char *host;\r
+- struct hostent *hp;\r
+ int level;\r
+ char user_name[256];\r
+ \r
+@@ -623,12 +648,18 @@\r
+ fatal(net, "All network ports in use");\r
+ \r
+ /* get name of connected client */\r
+- hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),\r
+- who->sin_family);\r
+- if (hp)\r
+- host = hp->h_name;\r
+- else\r
+- host = inet_ntoa(who->sin_addr);\r
++ int error = -1;\r
++ char namebuf[255];\r
++\r
++ error = getnameinfo(who, wholen, namebuf, sizeof(namebuf), NULL, 0, 0);\r
++ \r
++ if (error) {\r
++ perror("getnameinfo: localhost");\r
++ perror(gai_strerror(error));\r
++ exit(1); \r
++ }\r
++ \r
++ host = namebuf;\r
+ \r
+ /*\r
+ * We must make a copy because Kerberos is probably going\r
+@@ -649,13 +680,21 @@\r
+ \r
+ /* Get local host name */\r
+ {\r
+- struct hostent *h;\r
++ struct addrinfo hints;\r
++ struct addrinfo *res;\r
++ int e;\r
++\r
++ memset(&hints, '\0', sizeof(hints));\r
++ hints.ai_socktype = SOCK_STREAM;\r
++ hints.ai_flags = AI_ADDRCONFIG;\r
++\r
+ gethostname(host_name, sizeof(host_name));\r
+- h = gethostbyname(host_name);\r
+- if (h) {\r
+- strncpy(host_name, h->h_name, sizeof(host_name));\r
+- host_name[sizeof(host_name)-1] = 0;\r
++ if ((e = getaddrinfo(host_name, NULL, &hints, &res)) != 0) {\r
++ perror("getaddrinfo: localhost");\r
++ perror(gai_strerror(e));\r
++ exit(1);\r
+ }\r
++ freeaddrinfo(res);\r
+ }\r
+ \r
+ #if defined(AUTHENTICATE) || defined(ENCRYPT)\r
--- /dev/null
+--- netkit-telnet-0.17.orig/telnetd/telnetd.c 2007-03-13 16:31:20.000000000 +0000
++++ netkit-telnet-0.17.orig/telnetd/telnetd.c 2007-03-13 16:31:26.000000000 +0000
+@@ -653,6 +653,11 @@ doit(struct sockaddr *who, socklen_t who
+
+ error = getnameinfo(who, wholen, namebuf, sizeof(namebuf), NULL, 0, 0);
+
++ /* if we can't get a hostname now, settle for an address */
++ if(error == EAI_AGAIN)
++ error = getnameinfo(who, wholen, namebuf, sizeof(namebuf),
++ NULL, 0, NI_NUMERICHOST);
++
+ if (error) {
+ perror("getnameinfo: localhost");
+ perror(gai_strerror(error));
+@@ -681,7 +686,7 @@ doit(struct sockaddr *who, socklen_t who
+ /* Get local host name */
+ {
+ struct addrinfo hints;
+- struct addrinfo *res;
++ struct addrinfo *res = 0;
+ int e;
+
+ memset(&hints, '\0', sizeof(hints));
+@@ -690,11 +695,14 @@ doit(struct sockaddr *who, socklen_t who
+
+ gethostname(host_name, sizeof(host_name));
+ if ((e = getaddrinfo(host_name, NULL, &hints, &res)) != 0) {
+- perror("getaddrinfo: localhost");
+- perror(gai_strerror(e));
+- exit(1);
++ if(e != EAI_AGAIN) {
++ fprintf(stderr, "getaddrinfo: localhost %s\n",
++ gai_strerror(e));
++ exit(1);
++ }
+ }
+- freeaddrinfo(res);
++ if(res)
++ freeaddrinfo(res);
+ }
+
+ #if defined(AUTHENTICATE) || defined(ENCRYPT)
+
--- /dev/null
+--- netkit-telnet-0.17.orig/telnetd/telnetd.c.reallynodns 2009-03-12 14:32:29.000000000 -0700
++++ netkit-telnet-0.17.orig/telnetd/telnetd.c 2009-03-12 14:51:59.000000000 -0700
+@@ -85,6 +85,7 @@
+ int keepalive = 1;
+ char *loginprg = _PATH_LOGIN;
+ char *progname;
++int lookupself = 1;
+
+ extern void usage(void);
+
+@@ -111,7 +112,7 @@
+
+ progname = *argv;
+
+- while ((ch = getopt(argc, argv, "d:a:e:lhnr:I:D:B:sS:a:X:L:")) != EOF) {
++ while ((ch = getopt(argc, argv, "d:a:e:lhnr:I:D:B:sS:a:X:L:N")) != EOF) {
+ switch(ch) {
+
+ #ifdef AUTHENTICATE
+@@ -210,6 +211,10 @@
+ keepalive = 0;
+ break;
+
++ case 'N':
++ lookupself = 0;
++ break;
++
+ #ifdef SecurID
+ case 's':
+ /* SecurID required */
+@@ -393,6 +398,7 @@
+ #endif
+ fprintf(stderr, " [-L login_program]");
+ fprintf(stderr, " [-n]");
++ fprintf(stderr, " [-N]");
+ #ifdef SecurID
+ fprintf(stderr, " [-s]");
+ #endif
+@@ -691,15 +697,20 @@
+
+ memset(&hints, '\0', sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+- hints.ai_flags = AI_ADDRCONFIG;
++ hints.ai_flags = AI_CANONNAME;
+
+ gethostname(host_name, sizeof(host_name));
+- if ((e = getaddrinfo(host_name, NULL, &hints, &res)) != 0) {
+- if(e != EAI_AGAIN) {
+- fprintf(stderr, "getaddrinfo: localhost %s\n",
+- gai_strerror(e));
+- exit(1);
+- }
++ /*
++ * Optionally canonicalize the local host name, in case
++ * gethostname() returns foo, we want foo.example.com
++ */
++ if (lookupself &&
++ (e = getaddrinfo(host_name, NULL, &hints, &res)) == 0) {
++ if (res->ai_canonname) {
++ strncpy(host_name, res->ai_canonname,
++ sizeof(host_name)-1);
++ host_name[sizeof(host_name)-1] = 0;
++ }
+ }
+ if(res)
+ freeaddrinfo(res);
+--- netkit-telnet-0.17.orig/telnetd/telnetd.8.reallynodns 2009-03-12 14:54:54.000000000 -0700
++++ netkit-telnet-0.17.orig/telnetd/telnetd.8 2009-03-12 14:56:58.000000000 -0700
+@@ -42,7 +42,7 @@
+ protocol server
+ .Sh SYNOPSIS
+ .Nm /usr/sbin/in.telnetd
+-.Op Fl hns
++.Op Fl hnNs
+ .Op Fl a Ar authmode
+ .Op Fl D Ar debugmode
+ .Op Fl L Ar loginprg
+@@ -175,6 +175,10 @@
+ if the client is still there, so that idle connections
+ from machines that have crashed or can no longer
+ be reached may be cleaned up.
++.It Fl N
++Do not use DNS to canonicalize the local hostname;
++.Fn gethostname 2
++returns a fully qualified name.
+ .It Fl s
+ This option is only enabled if
+ .Nm telnetd
--- /dev/null
+diff -ru netkit-telnet-0.17.orig/telnet/main.c netkit-telnet-0.17/telnet/main.c
+--- netkit-telnet-0.17.orig/telnet/main.c 2003-05-15 20:07:40.000000000 +0200
++++ netkit-telnet-0.17/telnet/main.c 2003-05-16 00:18:28.000000000 +0200
+@@ -143,7 +143,7 @@
+ while ((ch = getopt(argc, argv, "78DEKLS:X:ab:cde:fFk:l:n:rt:x")) != -1) {
+ switch(ch) {
+ case '8':
+- eight = 3; /* binary output and input */
++ binary = 3; /* send TELNET BINARY option for output and input */
+ break;
+ case '7':
+ eight = 0;
+@@ -165,7 +165,7 @@
+ #endif
+ break;
+ case 'L':
+- eight |= 2; /* binary output only */
++ binary = 2; /* send TELNET BINARY option for output only */
+ break;
+ case 'S':
+ {
+diff -ru netkit-telnet-0.17.orig/telnet/telnet.1 netkit-telnet-0.17/telnet/telnet.1
+--- netkit-telnet-0.17.orig/telnet/telnet.1 2003-05-15 20:07:40.000000000 +0200
++++ netkit-telnet-0.17/telnet/telnet.1 2003-05-15 23:38:37.000000000 +0200
+@@ -76,6 +76,8 @@
+ .Pp
+ The options are as follows:
+ .Bl -tag -width Ds
++.It Fl 7
++Strip 8th bit on input and output. Telnet is 8-bit clean by default but doesn't send the TELNET BINARY option unless forced.
+ .It Fl 8
+ Specifies an 8-bit data path.
+ This causes an attempt to negotiate the
--- /dev/null
+--- netkit-telnet-0.17/telnet/telnet.c.CAN-2005-468_469 2005-03-17 13:48:58.000000000 +0100
++++ netkit-telnet-0.17/telnet/telnet.c 2005-03-17 14:02:27.000000000 +0100
+@@ -1310,22 +1310,66 @@
+ }
+
+
+-unsigned char slc_reply[128];
++#define SLC_REPLY_SIZE 128
++unsigned char *slc_reply;
+ unsigned char *slc_replyp;
++unsigned char *slc_replyend;
+
+ void
+ slc_start_reply(void)
+ {
++ slc_reply = (unsigned char *)malloc(SLC_REPLY_SIZE);
++ if (slc_reply == NULL) {
++/*@*/ printf("slc_start_reply: malloc()/realloc() failed!!!\n");
++ slc_reply = slc_replyp = slc_replyend = NULL;
++ return;
++ }
++
+ slc_replyp = slc_reply;
++ slc_replyend = slc_reply + SLC_REPLY_SIZE;
+ *slc_replyp++ = IAC;
+ *slc_replyp++ = SB;
+ *slc_replyp++ = TELOPT_LINEMODE;
+ *slc_replyp++ = LM_SLC;
+ }
+
++static int
++slc_assure_buffer(int want_len);
++
++ static int
++slc_assure_buffer(int want_len)
++{
++ if ((slc_replyp + want_len) >= slc_replyend) {
++ int len;
++ int old_len = slc_replyp - slc_reply;
++ unsigned char *p;
++
++ len = old_len
++ + (want_len / SLC_REPLY_SIZE + 1) * SLC_REPLY_SIZE;
++ p = (unsigned char *)realloc(slc_reply, len);
++ if (p == NULL)
++ free(slc_reply);
++ slc_reply = p;
++ if (slc_reply == NULL) {
++/*@*/ printf("slc_add_reply: realloc() failed!!!\n");
++ slc_reply = slc_replyp = slc_replyend = NULL;
++ return 1;
++ }
++ slc_replyp = slc_reply + old_len;
++ slc_replyend = slc_reply + len;
++ }
++ return 0;
++}
++
+ void
+ slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
+ {
++ if (slc_assure_buffer(6))
++ return;
++
++ if (slc_replyp == NULL)
++ return;
++
+ if ((*slc_replyp++ = func) == IAC)
+ *slc_replyp++ = IAC;
+ if ((*slc_replyp++ = flags) == IAC)
+@@ -1339,6 +1383,12 @@
+ {
+ int len;
+
++ if (slc_assure_buffer(2))
++ return;
++
++ if (slc_replyp == NULL)
++ return;
++
+ *slc_replyp++ = IAC;
+ *slc_replyp++ = SE;
+ len = slc_replyp - slc_reply;
+@@ -1456,7 +1506,7 @@
+ }
+ }
+
+-#define OPT_REPLY_SIZE 256
++#define OPT_REPLY_SIZE 1024
+ unsigned char *opt_reply;
+ unsigned char *opt_replyp;
+ unsigned char *opt_replyend;
+@@ -1490,10 +1540,38 @@
+ env_opt_start_info(void)
+ {
+ env_opt_start();
+- if (opt_replyp)
++ if (opt_replyp && (opt_replyp > opt_reply))
+ opt_replyp[-1] = TELQUAL_INFO;
+ }
+
++static int
++env_opt_assure_buffer(int want_len);
++
++ static int
++env_opt_assure_buffer(int want_len)
++{
++ if ((opt_replyp + want_len) >= opt_replyend) {
++ int len;
++ unsigned char *p;
++ int old_len = opt_replyp - opt_reply;
++
++ len = old_len
++ + (want_len / OPT_REPLY_SIZE + 1) * OPT_REPLY_SIZE;
++ p = (unsigned char *)realloc(opt_reply, len);
++ if (p == NULL)
++ free(opt_reply);
++ opt_reply = p;
++ if (opt_reply == NULL) {
++/*@*/ printf("env_opt_add: realloc() failed!!!\n");
++ opt_reply = opt_replyp = opt_replyend = NULL;
++ return 1;
++ }
++ opt_replyp = opt_reply + old_len;
++ opt_replyend = opt_reply + len;
++ }
++ return 0;
++}
++
+ void
+ env_opt_add(unsigned char *ep)
+ {
+@@ -1515,25 +1593,12 @@
+ return;
+ }
+ vp = env_getvalue(ep, 1);
+- if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
+- strlen((char *)ep) + 6 > opt_replyend)
+- {
+- int len;
+- unsigned char *p;
+- opt_replyend += OPT_REPLY_SIZE;
+- len = opt_replyend - opt_reply;
+- p = (unsigned char *)realloc(opt_reply, len);
+- if (p == NULL)
+- free(opt_reply);
+- opt_reply = p;
+- if (opt_reply == NULL) {
+-/*@*/ printf("env_opt_add: realloc() failed!!!\n");
+- opt_reply = opt_replyp = opt_replyend = NULL;
+- return;
+- }
+- opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
+- opt_replyend = opt_reply + len;
+- }
++
++ /* use the double length in case it gots escaped */
++ if (env_opt_assure_buffer((vp ? strlen((char *)vp)*2 : 0) +
++ strlen((char *)ep)*2 + 6))
++ return;
++
+ if (opt_welldefined((char *)ep))
+ #ifdef OLD_ENVIRON
+ if (telopt_environ == TELOPT_OLD_ENVIRON)
+@@ -1588,8 +1653,14 @@
+ {
+ int len;
+
++ if (opt_reply == NULL) /*XXX*/
++ return; /*XXX*/
++
++
+ len = opt_replyp - opt_reply + 2;
+ if (emptyok || len > 6) {
++ if (env_opt_assure_buffer(2))
++ return;
+ *opt_replyp++ = IAC;
+ *opt_replyp++ = SE;
+ if (NETROOM() > len) {
--- /dev/null
+diff -ur netkit-telnet-0.17/telnetd/setproctitle.c netkit-telnet-0.17.new/telnetd/setproctitle.c
+--- netkit-telnet-0.17/telnetd/setproctitle.c 1999-12-11 00:06:39.000000000 +0100
++++ netkit-telnet-0.17.new/telnetd/setproctitle.c 2004-06-28 16:48:51.153514392 +0200
+@@ -139,7 +139,7 @@
+ (void) strcpy(Argv[0], buf);
+ p = &Argv[0][i];
+ while (p < LastArgv)
+- *p++ = ' ';
++ *p++ = '\0';
+ Argv[1] = NULL;
+ }
+
--- /dev/null
+--- netkit-telnet-0.17/telnetd/telnetd.c.cleanup_race 2005-01-11 18:39:49.578123000 -0500
++++ netkit-telnet-0.17/telnetd/telnetd.c 2005-01-11 18:42:45.909616000 -0500
+@@ -1081,6 +1081,8 @@
+ if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
+ ptyflush();
+ }
++ /* to avoid a race for wtmp lock */
++ signal(SIGCHLD, SIG_IGN);
+ cleanup(0);
+ } /* end of telnet */
+
--- /dev/null
+--- netkit-telnet-0.17/configure.confverb 2000-07-29 20:00:29.000000000 +0200
++++ netkit-telnet-0.17/configure 2004-07-05 10:50:36.492963840 +0200
+@@ -263,14 +263,19 @@
+ cat <<EOF >__conftest.cc
+ #include <unistd.h>
+ #include <signal.h>
+-int count=0;
++volatile int count=0;
+ void handle(int foo) { count++; }
+ int main() {
++ sigset_t sset;
+ int pid=getpid();
++ sigemptyset(&sset);
++ sigaddset(&sset, SIGINT);
++ sigprocmask(SIG_UNBLOCK, &sset, NULL);
+ signal(SIGINT, handle);
+ kill(pid,SIGINT);
+ kill(pid,SIGINT);
+ kill(pid,SIGINT);
++ sleep(1);
+ if (count!=3) return 1;
+ return 0;
+ }
--- /dev/null
+--- netkit-telnet-0.17-pre-20000204/telnet/commands.c.env Thu Apr 8 19:30:20 1999
++++ netkit-telnet-0.17-pre-20000204/telnet/commands.c Tue May 16 17:19:47 2000
+@@ -1815,11 +1815,11 @@
+ }
+
+ unsigned char *
+-env_getvalue(unsigned char *var)
++env_getvalue(unsigned char *var, int exported_only)
+ {
+- struct env_lst *ep;
++ struct env_lst *ep = env_find(var);
+
+- if ((ep = env_find(var)))
++ if (ep && (!exported_only || ep->export))
+ return(ep->value);
+ return(NULL);
+ }
+--- netkit-telnet-0.17-pre-20000204/telnet/telnet.c.env Tue May 16 17:19:47 2000
++++ netkit-telnet-0.17-pre-20000204/telnet/telnet.c Tue May 16 17:19:47 2000
+@@ -438,7 +438,7 @@
+ #endif
+
+ case TELOPT_XDISPLOC: /* X Display location */
+- if (env_getvalue((unsigned char *)"DISPLAY"))
++ if (env_getvalue((unsigned char *)"DISPLAY", 0))
+ new_state_ok = 1;
+ break;
+
+@@ -693,7 +693,7 @@
+ resettermname = 0;
+ if (tnamep && tnamep != unknown)
+ free(tnamep);
+- if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
++ if ((tname = (char *)env_getvalue((unsigned char *)"TERM", 0)) &&
+ (setupterm(tname, 1, &errret) == 0)) {
+ tnamep = mklist(ttytype, tname);
+ } else {
+@@ -870,7 +870,7 @@
+ unsigned char temp[50], *dp;
+ int len;
+
+- if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
++ if ((dp = env_getvalue((unsigned char *)"DISPLAY", 0)) == NULL) {
+ /*
+ * Something happened, we no longer have a DISPLAY
+ * variable. So, turn off the option.
+@@ -1527,7 +1527,7 @@
+ env_opt_add(ep);
+ return;
+ }
+- vp = env_getvalue(ep);
++ vp = env_getvalue(ep, 1);
+ if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
+ strlen((char *)ep) + 6 > opt_replyend)
+ {
+@@ -2170,7 +2170,7 @@
+ send_will(TELOPT_LINEMODE, 1);
+ send_will(TELOPT_NEW_ENVIRON, 1);
+ send_do(TELOPT_STATUS, 1);
+- if (env_getvalue((unsigned char *)"DISPLAY"))
++ if (env_getvalue((unsigned char *)"DISPLAY", 0))
+ send_will(TELOPT_XDISPLOC, 1);
+ if (binary)
+ tel_enter_binary(binary);
+--- netkit-telnet-0.17-pre-20000204/telnet/externs.h.env Mon Feb 8 15:56:11 1999
++++ netkit-telnet-0.17-pre-20000204/telnet/externs.h Tue May 16 17:19:47 2000
+@@ -203,7 +203,7 @@
+ void env_send (unsigned char *);
+ void env_list (void);
+ unsigned char * env_default(int init, int welldefined);
+-unsigned char * env_getvalue(unsigned char *var);
++unsigned char * env_getvalue(unsigned char *var, int exported_only);
+
+ void set_escape_char(char *s);
+ unsigned long sourceroute(char *arg, char **cpp, int *lenp);
+@@ -335,7 +335,7 @@
+ void env_opt_end (int);
+
+ unsigned char *env_default (int, int);
+-unsigned char *env_getvalue (unsigned char *);
++unsigned char *env_getvalue (unsigned char *, int);
+
+ int get_status (void);
+ int dosynch (void);
--- /dev/null
+diff -up netkit-telnet-0.17/telnet/sys_bsd.c.errnosysbsd netkit-telnet-0.17/telnet/sys_bsd.c
+--- netkit-telnet-0.17/telnet/sys_bsd.c.errnosysbsd 2007-09-20 10:57:58.000000000 +0200
++++ netkit-telnet-0.17/telnet/sys_bsd.c 2007-09-20 11:10:08.000000000 +0200
+@@ -375,6 +375,7 @@ TerminalNewMode(int f)
+ int onoff;
+ int old;
+ cc_t esc;
++ int err;
+
+ globalmode = f&~MODE_FORCE;
+ if (prevmode == f)
+@@ -407,6 +408,12 @@ TerminalNewMode(int f)
+ tcsetattr(tin, TCSADRAIN, &tmp_tc);
+ #endif /* USE_TERMIO */
+ old = ttyflush(SYNCHing|flushout);
++ if (old < 0) {
++ err = errno;
++ if (! ((err == EINTR) || (err == EAGAIN) || (err == ENOSPC))) {
++ break;
++ }
++ }
+ } while (old < 0 || old > 1);
+ }
+
--- /dev/null
+--- netkit-telnet-0.17/telnetd/utility.c.issue Sun Dec 12 09:59:45 1999
++++ netkit-telnet-0.17/telnetd/utility.c Wed Jul 18 11:14:11 2001
+@@ -460,13 +460,13 @@
+ putlocation = where;
+
+ while (*cp) {
+- if (*cp != '%') {
++ if (*cp != '%' && *cp != '\\') {
+ putchr(*cp++);
+ continue;
+ }
+ switch (*++cp) {
+
+- case 't':
++ case 'l':
+ slash = strrchr(line, '/');
+ if (slash == NULL)
+ putstr(line);
+@@ -474,21 +474,28 @@
+ putstr(slash+1);
+ break;
+
++ case 'n':
+ case 'h':
+ putstr(editedhost);
+ break;
+
++ case 't':
+ case 'd':
+ (void)time(&t);
+ (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
+ putstr(db);
+ break;
+
++ case '\\':
++ putchr('\\');
++ break;
++
+ case '%':
+ putchr('%');
+ break;
+
+ case 'D':
++ case 'o':
+ {
+ char buff[128];
+
+@@ -515,7 +522,7 @@
+ c = fgetc(fp);
+ } while (c != EOF && c != '\n');
+ continue;
+- } else if (c == '%') {
++ } else if (c == '%' || c == '\\') {
+ buff[0] = c;
+ c = fgetc(fp);
+ if (c == EOF) break;
+--- netkit-telnet-0.17/telnetd/issue.net.5.issue Sun Jul 30 19:57:09 2000
++++ netkit-telnet-0.17/telnetd/issue.net.5 Wed Jul 18 11:03:09 2001
+@@ -15,16 +15,17 @@
+ .Pa /etc/issue.net
+ is a text file which contains a message or system identification to be
+ printed before the login prompt of a telnet session. It may contain
+-various `%-char' sequences. The following sequences are supported by
++various `%-char' (or, alternatively, '\\-char') sequences. The following
++sequences are supported by
+ .Ic telnetd :
+ .Bl -tag -offset indent -compact -width "abcde"
+-.It %t
++.It %l
+ - show the current tty
+-.It %h
++.It %h, %n
+ - show the system node name (FQDN)
+-.It %D
++.It %D, %o
+ - show the name of the NIS domain
+-.It %d
++.It %d, %t
+ - show the current time and date
+ .It %s
+ - show the name of the operating system
--- /dev/null
+diff -u telnet/commands.c telnet.new/commands.c
+--- telnet/commands.c Sat Sep 1 12:55:18 2001
++++ telnet.new/commands.c Sat Sep 1 12:54:36 2001
+@@ -2354,6 +2354,7 @@
+ hints.ai_flags = AI_CANONNAME;
+ if (portp == NULL) {
+ portp = "telnet";
++ telnetport = 1;
+ } else if (*portp == '-') {
+ portp++;
+ telnetport = 1;
+@@ -2397,7 +2398,6 @@
+ if (error) {
+ warn("%s: %s", aliasp, gai_strerror(error));
+ close(net);
+- freeaddrinfo(ares);
+ continue;
+ }
+ if (bind(net, ares->ai_addr, ares->ai_addrlen) < 0) {
+@@ -2414,7 +2414,7 @@
+ perror("setsockopt (IP_OPTIONS)");
+ #endif
+ #if defined(IPPROTO_IP) && defined(IP_TOS)
+- {
++ if (res->ai_family == AF_INET) {
+ # if defined(HAS_GETTOS)
+ struct tosent *tp;
+ if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+@@ -2438,7 +2438,7 @@
+ char hbuf[NI_MAXHOST];
+
+ if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
+- NULL, 0, NI_NUMERICHOST) != 0) {
++ NULL, 0, niflags) != 0) {
+ strcpy(hbuf, "(invalid)");
+ }
+ fprintf(stderr, "telnet: connect to address %s: %s\n", hbuf,
--- /dev/null
+diff -up netkit-telnet-0.17/telnetd/ext.h.sa-01-49 netkit-telnet-0.17/telnetd/ext.h
+--- netkit-telnet-0.17/telnetd/ext.h.sa-01-49 1999-12-12 15:59:44.000000000 +0100
++++ netkit-telnet-0.17/telnetd/ext.h 2011-01-20 22:39:54.000000000 +0100
+@@ -86,7 +86,10 @@ extern char *neturg; /* one past last b
+ extern int pcc, ncc;
+
+ /* printf into netobuf */
+-void netoprintf(const char *fmt, ...) __attribute((format (printf, 1, 2)));
++/* void netoprintf(const char *fmt, ...) __attribute((format (printf, 1, 2))); */
++#define netoprintf output_data
++int output_data(const char *, ...) __attribute((format (printf, 1, 2)));
++void output_datalen(const char *, int);
+
+ extern int pty, net;
+ extern char *line;
+@@ -182,7 +185,10 @@ void tty_setsofttab(int);
+ void tty_tspeed(int);
+ void willoption(int);
+ void wontoption(int);
++
++#if 0
+ void writenet(unsigned char *, int);
++#endif
+
+ #if defined(ENCRYPT)
+ extern void (*encrypt_output)(unsigned char *, int);
+diff -up netkit-telnet-0.17/telnetd/slc.c.sa-01-49 netkit-telnet-0.17/telnetd/slc.c
+--- netkit-telnet-0.17/telnetd/slc.c.sa-01-49 1999-12-12 15:59:44.000000000 +0100
++++ netkit-telnet-0.17/telnetd/slc.c 2011-01-20 22:39:54.000000000 +0100
+@@ -183,7 +183,7 @@ int end_slc(unsigned char **bufp) {
+ else {
+ snprintf(slcbuf+slcoff, sizeof(slcbuf)-slcoff, "%c%c", IAC, SE);
+ slcoff += 2;
+- writenet(slcbuf, slcoff);
++ output_datalen(slcbuf, slcoff);
+ netflush(); /* force it out immediately */
+ }
+ }
+diff -up netkit-telnet-0.17/telnetd/state.c.sa-01-49 netkit-telnet-0.17/telnetd/state.c
+--- netkit-telnet-0.17/telnetd/state.c.sa-01-49 1999-12-12 20:41:44.000000000 +0100
++++ netkit-telnet-0.17/telnetd/state.c 2011-01-20 22:43:34.000000000 +0100
+@@ -37,6 +37,7 @@
+ char state_rcsid[] =
+ "$Id: state.c,v 1.12 1999/12/12 19:41:44 dholland Exp $";
+
++#include <stdarg.h>
+ #include "telnetd.h"
+
+ int not42 = 1;
+@@ -1365,7 +1366,7 @@ void send_status(void) {
+ ADD(IAC);
+ ADD(SE);
+
+- writenet(statusbuf, ncp - statusbuf);
++ output_datalen(statusbuf, ncp - statusbuf);
+ netflush(); /* Send it on its way */
+
+ DIAG(TD_OPTIONS, {printsub('>', statusbuf, ncp - statusbuf); netflush();});
+diff -up netkit-telnet-0.17/telnetd/termstat.c.sa-01-49 netkit-telnet-0.17/telnetd/termstat.c
+--- netkit-telnet-0.17/telnetd/termstat.c.sa-01-49 1999-12-12 15:59:45.000000000 +0100
++++ netkit-telnet-0.17/telnetd/termstat.c 2011-01-20 22:39:54.000000000 +0100
+@@ -128,7 +128,6 @@ static int _terminit = 0;
+ void
+ localstat()
+ {
+- void netflush();
+ int need_will_echo = 0;
+
+ /*
+diff -up netkit-telnet-0.17/telnetd/utility.c.sa-01-49 netkit-telnet-0.17/telnetd/utility.c
+--- netkit-telnet-0.17/telnetd/utility.c.sa-01-49 2011-01-20 22:39:54.000000000 +0100
++++ netkit-telnet-0.17/telnetd/utility.c 2011-01-20 22:48:02.000000000 +0100
+@@ -38,8 +38,10 @@ char util_rcsid[] =
+ "$Id: utility.c,v 1.11 1999/12/12 14:59:45 dholland Exp $";
+
+ #define PRINTOPTIONS
++#define _GNU_SOURCE
+
+ #include <stdarg.h>
++#include <stdio.h>
+ #include <sys/utsname.h>
+
+ #ifdef AUTHENTICATE
+@@ -52,6 +54,53 @@ char util_rcsid[] =
+ * utility functions performing io related tasks
+ */
+
++/*
++ * This function appends data to nfrontp and advances nfrontp.
++ * Returns the number of characters written altogether (the
++ * buffer may have been flushed in the process).
++ */
++
++int
++output_data(const char *format, ...)
++{
++ va_list args;
++ int len;
++ char *buf;
++
++ va_start(args, format);
++ if ((len = vasprintf(&buf, format, args)) == -1)
++ return -1;
++ output_datalen(buf, len);
++ va_end(args);
++ free(buf);
++ return (len);
++}
++
++void
++output_datalen(const char *buf, int len)
++{
++ int remaining, copied;
++
++ remaining = BUFSIZ - (nfrontp - netobuf);
++ while (len > 0) {
++ /* Free up enough space if the room is too low*/
++ if ((len > BUFSIZ ? BUFSIZ : len) > remaining) {
++ netflush();
++ remaining = BUFSIZ - (nfrontp - netobuf);
++ }
++
++ /* Copy out as much as will fit */
++ copied = remaining > len ? len : remaining;
++ memmove(nfrontp, buf, copied);
++ nfrontp += copied;
++ len -= copied;
++ remaining -= copied;
++ buf += copied;
++ }
++ return;
++}
++
++/**
+ void
+ netoprintf(const char *fmt, ...)
+ {
+@@ -67,7 +116,7 @@ netoprintf(const char *fmt, ...)
+ va_end(ap);
+
+ if (len<0 || len==maxsize) {
+- /* didn't fit */
++ / * did not fit * /
+ netflush();
+ }
+ else {
+@@ -76,6 +125,7 @@ netoprintf(const char *fmt, ...)
+ }
+ nfrontp += len;
+ }
++*/
+
+ /*
+ * ttloop
+@@ -273,10 +323,15 @@ netflush(void)
+ int n;
+
+ if ((n = nfrontp - nbackp) > 0) {
++
++#if 0
++ /* XXX This causes output_data() to recurse and die */
+ DIAG(TD_REPORT,
+ { netoprintf("td: netflush %d chars\r\n", n);
+ n = nfrontp - nbackp; /* update count */
+ });
++#endif
++
+ #if defined(ENCRYPT)
+ if (encrypt_output) {
+ char *s = nclearto ? nclearto : nbackp;
+@@ -310,11 +365,14 @@ netflush(void)
+ }
+ }
+ }
+- if (n < 0) {
+- if (errno == EWOULDBLOCK || errno == EINTR)
+- return;
+- cleanup(0);
+- }
++
++ if (n == -1) {
++ if (errno == EWOULDBLOCK || errno == EINTR)
++ return;
++ cleanup(0);
++ /* NOTREACHED */
++ }
++
+ nbackp += n;
+ #if defined(ENCRYPT)
+ if (nbackp > nclearto)
+@@ -332,7 +390,7 @@ netflush(void)
+ return;
+ } /* end of netflush */
+
+-
++#if 0
+ /*
+ * writenet
+ *
+@@ -355,7 +413,7 @@ void writenet(register unsigned char *pt
+ nfrontp += len;
+
+ } /* end of writenet */
+-
++#endif
+
+ /*
+ * miscellaneous functions doing a variety of little jobs follow ...
--- /dev/null
+diff -uNr telnet/Makefile telnet.obsd-cvs/Makefile
+--- telnet/Makefile Mon Jul 27 18:25:13 1998
++++ telnet.obsd-cvs/Makefile Sat Mar 10 10:54:26 2001
+@@ -36,22 +36,20 @@
+
+ PROG= telnet
+
+-CFLAGS+=-DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DSKEY -Dunix
+-CFLAGS+=-DENV_HACK -D_USE_OLD_CURSES_
++CFLAGS+=-DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK -DSKEY -Dunix
+ CFLAGS+=-I${.CURDIR}/../../lib
+-LDADD+= -locurses -ltelnet
+-DPADD= ${LIBOLDCURSES} ${LIBTELNET}
++LDADD+= -lcurses -ltelnet
++DPADD= ${LIBCURSES} ${LIBTELNET
+
+ SRCS= authenc.c commands.c main.c network.c ring.c sys_bsd.c telnet.c \
+ terminal.c tn3270.c utilities.c
+
+ .include <bsd.own.mk> # for KERBEROS
+
+-.if (${KERBEROS} == "yes")
++.if (${KERBEROS:L} == "yes")
+ CFLAGS+=-DENCRYPTION -DAUTHENTICATION -DKRB4
+ LDADD+= -lkrb -ldes
+ DPADD+= ${LIBDES} ${LIBKRB}
+ .endif
+
+ .include <bsd.prog.mk>
+-
+diff -uNr telnet/commands.c telnet.obsd-cvs/commands.c
+--- telnet/commands.c Fri Apr 9 02:30:20 1999
++++ telnet.obsd-cvs/commands.c Sat Mar 10 10:51:22 2001
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: commands.c,v 1.20 1999/01/04 07:55:05 art Exp $ */
++/* $OpenBSD: commands.c,v 1.34 2000/11/08 21:49:44 aaron Exp $ */
+ /* $NetBSD: commands.c,v 1.14 1996/03/24 22:03:48 jtk Exp $ */
+
+ /*
+@@ -69,7 +69,7 @@
+ int status;
+
+ if(argc != 3) {
+- printf("%s sequence challenge\n", argv[0]);
++ printf("usage: %s sequence challenge\n", argv[0]);
+ return 0;
+ }
+
+@@ -2175,17 +2175,19 @@
+ int gotmachine = 0;
+ int l1 = strlen(m1);
+ int l2 = strlen(m2);
+- char m1save[64];
++ char m1save[MAXHOSTNAMELEN];
+
+ if (skiprc)
+ return;
+
+- strcpy(m1save, m1);
++ strncpy(m1save, m1, sizeof(m1save));
+ m1 = m1save;
+
+ if (rcname[0] == 0) {
+ char *home = getenv("HOME");
+
++ if (home == NULL || *home == '\0')
++ return;
+ snprintf (rcname, sizeof(rcname), "%s/.telnetrc",
+ home ? home : "");
+ }
+@@ -2248,15 +2250,9 @@
+ int
+ tn(int argc, char *argv[])
+ {
+- struct hostent *host = 0, *alias = 0;
+-#if defined(AF_INET6)
+- struct sockaddr_in6 sin6;
+-#endif
++ struct addrinfo hints, *res, *res0;
++ int error;
+ struct sockaddr_in sin;
+- struct sockaddr_in ladr;
+- struct sockaddr *sa;
+- int sa_size;
+- struct servent *sp = 0;
+ unsigned long temp;
+ #if !defined(__linux__)
+ extern char *inet_ntoa();
+@@ -2266,15 +2262,18 @@
+ int srlen;
+ #endif
+ char *cmd, *hostp = 0, *portp = 0, *user = 0, *aliasp = 0;
+- int family, port = 0;
+-
++ int retry;
++#ifdef NI_WITHSCOPEID
++ const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
++#else
++ const int niflags = NI_NUMERICHOST;
++#endif
++
+ /* clear the socket address prior to use */
+ memset((char *)&sin, 0, sizeof(sin));
+
+ if (connected) {
+ printf("?Already connected to %s\r\n", hostname);
+- seteuid(getuid());
+- setuid(getuid());
+ return 0;
+ }
+ if (argc < 2) {
+@@ -2324,8 +2323,6 @@
+ }
+ usage:
+ printf("usage: %s [-l user] [-a] host-name [port]\r\n", cmd);
+- seteuid(getuid());
+- setuid(getuid());
+ return 0;
+ }
+ if (hostp == 0)
+@@ -2340,185 +2337,80 @@
+ temp = sourceroute(hostp, &srp, &srlen);
+ if (temp == 0) {
+ herror(srp);
+- seteuid(getuid());
+- setuid(getuid());
+ return 0;
+ } else if (temp == -1) {
+ printf("Bad source route option: %s\r\n", hostp);
+- seteuid(getuid());
+- setuid(getuid());
+ return 0;
+ } else {
+ abort();
+ }
+- } else {
+-#endif
+- memset (&sin, 0, sizeof(sin));
+-#if defined(HAVE_INET_PTON) && defined(AF_INET6)
+- memset (&sin6, 0, sizeof(sin6));
+-
+- if(inet_pton(AF_INET6, hostp, &sin6.sin6_addr)) {
+- sin6.sin6_family = family = AF_INET6;
+- sa = (struct sockaddr *)&sin6;
+- sa_size = sizeof(sin6);
+- strcpy(_hostname, hostp);
+- hostname =_hostname;
+- } else
+-#endif
+- if(inet_aton(hostp, &sin.sin_addr)){
+- sin.sin_family = family = AF_INET;
+- sa = (struct sockaddr *)&sin;
+- sa_size = sizeof(sin);
+- strcpy(_hostname, hostp);
+- hostname = _hostname;
+- } else {
+-#ifdef HAVE_GETHOSTBYNAME2
+- host = gethostbyname2(hostp, AF_INET6);
+- if(host == NULL)
+- host = gethostbyname2(hostp, AF_INET);
+-#else
+- host = gethostbyname(hostp);
+-#endif
+- if (host) {
+- strncpy(_hostname, host->h_name, sizeof(_hostname));
+- family = host->h_addrtype;
+-
+- switch(family) {
+- case AF_INET:
+- memset(&sin, 0, sizeof(sin));
+- sa_size = sizeof(sin);
+- sa = (struct sockaddr *)&sin;
+- sin.sin_family = family;
+-
+- memcpy(&sin.sin_addr, *host->h_addr_list, sizeof(struct in_addr));
+- break;
+-#if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6)
+- case AF_INET6:
+- memset(&sin6, 0, sizeof(sin6));
+- sa_size = sizeof(sin6);
+- sa = (struct sockaddr *)&sin6;
+- sin6.sin6_family = family;
+- memcpy(&sin6.sin6_addr, *host->h_addr_list, sizeof(struct in6_addr));
+- break;
+-#endif
+- default:
+- fprintf(stderr, "Bad address family: %d\n", family);
+- return 0;
+- }
+-
+- _hostname[sizeof(_hostname)-1] = '\0';
+- hostname = _hostname;
+- } else {
+- herror(hostp);
+- seteuid(getuid());
+- setuid(getuid());
+- return 0;
+- }
+- }
+-#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
+- }
++ } else
+ #endif
+- if (portp) {
+- if (*portp == '-') {
+- portp++;
+- telnetport = 1;
+- } else
+- telnetport = 0;
+- port = atoi(portp);
+- if (port == 0) {
+- sp = getservbyname(portp, "tcp");
+- if (sp)
+- port = sp->s_port;
+- else {
+- printf("%s: bad port number\r\n", portp);
+- seteuid(getuid());
+- setuid(getuid());
+- return 0;
+- }
+- } else {
+- port = htons(port);
+- }
+- } else {
+- if (sp == 0) {
+- sp = getservbyname("telnet", "tcp");
+- if (sp == 0) {
+- fprintf(stderr, "telnet: tcp/telnet: unknown service\r\n");
+- seteuid(getuid());
+- setuid(getuid());
+- return 0;
+- }
+- port = sp->s_port;
++ {
++ hostname = hostp;
++ memset(&hints, 0, sizeof(hints));
++ hints.ai_family = PF_UNSPEC;
++ hints.ai_socktype = SOCK_STREAM;
++ hints.ai_flags = AI_CANONNAME;
++ if (portp == NULL) {
++ portp = "telnet";
++ } else if (*portp == '-') {
++ portp++;
++ telnetport = 1;
++ }
++ h_errno = 0;
++ error = getaddrinfo(hostp, portp, &hints, &res0);
++ if (error) {
++ if (error == EAI_SERVICE)
++ warnx("%s: bad port", portp);
++ else
++ warnx("%s: %s", hostp, gai_strerror(error));
++ if (h_errno)
++ herror(hostp);
++ return 0;
+ }
+- telnetport = 1;
+ }
+- switch(family) {
+- case AF_INET:
+- sin.sin_port = port;
+- printf("Trying %s...\r\n", inet_ntoa(sin.sin_addr));
+- break;
+-#if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6)
+- case AF_INET6: {
+-#ifndef INET6_ADDRSTRLEN
+-#define INET6_ADDRSTRLEN 46
+-#endif
+
+- char buf[INET6_ADDRSTRLEN];
+-
+- sin6.sin6_port = port;
+-#ifdef HAVE_INET_NTOP
+- printf("Trying %s...\r\n", inet_ntop(AF_INET6,
+- &sin6.sin6_addr,
+- buf,
+- sizeof(buf)));
+-#endif
+- break;
+- }
+-#endif
+- default:
+- abort();
+- }
+-
+- do {
+- net = socket(family, SOCK_STREAM, 0);
+- seteuid(getuid());
+- setuid(getuid());
+- if (net < 0) {
+- perror("telnet: socket");
+- return 0;
++ net = -1;
++ retry = 0;
++ for (res = res0; res; res = res->ai_next) {
++ if (1 /* retry */) {
++ char hbuf[NI_MAXHOST];
++
++ if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
++ NULL, 0, niflags) != 0) {
++ strcpy(hbuf, "(invalid)");
++ }
++ printf("Trying %s...\r\n", hbuf);
+ }
++ net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
++ if (net < 0)
++ continue;
++
+ if (aliasp) {
+- memset ((caddr_t)&ladr, 0, sizeof (ladr));
+- temp = inet_addr(aliasp);
+- if (temp != INADDR_NONE) {
+- ladr.sin_addr.s_addr = temp;
+- ladr.sin_family = AF_INET;
+- alias = gethostbyaddr((char *)&temp, sizeof(temp), AF_INET);
+- } else {
+- alias = gethostbyname(aliasp);
+- if (alias) {
+- ladr.sin_family = alias->h_addrtype;
+-#if defined(h_addr) /* In 4.3, this is a #define */
+- memmove((caddr_t)&ladr.sin_addr,
+- alias->h_addr_list[0], alias->h_length);
+-#else /* defined(h_addr) */
+- memmove((caddr_t)&ladr.sin_addr, alias->h_addr,
+- alias->h_length);
+-#endif /* defined(h_addr) */
+- } else {
+- herror(aliasp);
+- return 0;
+- }
++ struct addrinfo ahints, *ares;
++ memset(&ahints, 0, sizeof(ahints));
++ ahints.ai_family = PF_UNSPEC;
++ ahints.ai_socktype = SOCK_STREAM;
++ ahints.ai_flags = AI_PASSIVE;
++ error = getaddrinfo(aliasp, "0", &ahints, &ares);
++ if (error) {
++ warn("%s: %s", aliasp, gai_strerror(error));
++ close(net);
++ freeaddrinfo(ares);
++ continue;
+ }
+- ladr.sin_port = htons(0);
+-
+- if (bind (net, (struct sockaddr *)&ladr, sizeof(ladr)) < 0) {
+- perror(aliasp);;
++ if (bind(net, ares->ai_addr, ares->ai_addrlen) < 0) {
++ perror(aliasp);
+ (void) close(net); /* dump descriptor */
+- return 0;
++ freeaddrinfo(ares);
++ continue;
+ }
++ freeaddrinfo(ares);
+ }
+ #if defined(IP_OPTIONS) && defined(IPPROTO_IP)
+- if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
++ if (srp && res->ai_family == AF_INET
++ && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
+ perror("setsockopt (IP_OPTIONS)");
+ #endif
+ #if defined(IPPROTO_IP) && defined(IP_TOS)
+@@ -2542,65 +2434,32 @@
+ perror("setsockopt (SO_DEBUG)");
+ }
+
+- if (connect(net, sa, sa_size) < 0) {
+- int retry = 0;
+-
+- if (host && host->h_addr_list[1]) {
+- int oerrno = errno;
+- retry = 1;
+-
+- switch(family) {
+- case AF_INET :
+- fprintf(stderr, "telnet: connect to address %s: ",
+- inet_ntoa(sin.sin_addr));
+- ++host->h_addr_list;
+- memcpy(&sin.sin_addr, *host->h_addr_list, sizeof(struct in_addr));
+- break;
+-#if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6)
+- case AF_INET6: {
+- char buf[INET6_ADDRSTRLEN];
+-
+- fprintf(stderr, "telnet: connect to address %s: ",
+- inet_ntop(AF_INET6, &sin6.sin6_addr, buf,
+- sizeof(buf)));
+- ++host->h_addr_list;
+- memcpy(&sin6.sin6_addr, *host->h_addr_list, sizeof(struct in6_addr));
+- break;
+- }
+-#endif
+- default:
+- abort();
+- }
+-
+- errno = oerrno;
+- perror(NULL);
+-
+- switch(family) {
+- case AF_INET :
+- printf("Trying %s...\r\n", inet_ntoa(sin.sin_addr));
+- break;
+-#if defined(AF_INET6) && defined(HAVE_STRUCT_SOCKADDR_IN6)
+- case AF_INET6: {
+- printf("Trying %s...\r\n", inet_ntop(AF_INET6,
+- &sin6.sin6_addr,
+- buf,
+- sizeof(buf)));
+- break;
+- }
+-#endif
+- }
+-
+- (void) NetClose(net);
+- continue;
++ if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
++ char hbuf[NI_MAXHOST];
++
++ if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
++ NULL, 0, NI_NUMERICHOST) != 0) {
++ strcpy(hbuf, "(invalid)");
+ }
+- perror("telnet: Unable to connect to remote host");
+- return 0;
++ fprintf(stderr, "telnet: connect to address %s: %s\n", hbuf,
++ strerror(errno));
++
++ close(net);
++ net = -1;
++ retry++;
++ continue;
+ }
++
+ connected++;
+ #if defined(AUTHENTICATION) || defined(ENCRYPTION)
+ auth_encrypt_connect(connected);
+ #endif /* defined(AUTHENTICATION) */
+- } while (connected == 0);
++ break;
++ }
++ freeaddrinfo(res0);
++ if (net < 0) {
++ return 0;
++ }
+ cmdrc(hostp, hostname);
+ if (autologin && user == NULL) {
+ struct passwd *pw;
+@@ -2652,6 +2511,9 @@
+ encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)",
+ #endif
+ zhelp[] = "suspend telnet",
++#ifdef SKEY
++ skeyhelp[] = "compute response to s/key challenge",
++#endif
+ shellhelp[] = "invoke a subshell",
+ envhelp[] = "change environment variables ('environ ?' for more)",
+ modestring[] = "try to enter line or character mode ('mode ?' for more)";
+@@ -2690,7 +2552,7 @@
+ { "environ", envhelp, env_cmd, 0 },
+ { "?", helphelp, help, 0 },
+ #if defined(SKEY)
+- { "skey", NULL, skey_calc, 0 },
++ { "skey", skeyhelp, skey_calc, 0 },
+ #endif
+ { 0, 0, 0, 0 }
+ };
+diff -uNr telnet/externs.h telnet.obsd-cvs/externs.h
+--- telnet/externs.h Mon Feb 8 22:56:11 1999
++++ telnet.obsd-cvs/externs.h Sat Mar 10 10:54:35 2001
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: externs.h,v 1.4 1998/03/12 17:31:32 deraadt Exp $ */
++/* $OpenBSD: externs.h,v 1.5 1998/03/12 2001/01/22 11:03:38 fgsch Exp $ */
+ /* $KTH: externs.h,v 1.16 1997/11/29 02:28:35 joda Exp $ */
+
+ /*
+@@ -447,7 +447,7 @@
+ *Ibackp, /* Oldest byte of 3270 data */
+ Ibuf[], /* 3270 buffer */
+ *Ifrontp, /* Where next 3270 byte goes */
+- tline[],
++ tline[200],
+ *transcom; /* Transparent command */
+
+ extern int
+diff -uNr telnet/main.c telnet.obsd-cvs/main.c
+--- telnet/main.c Wed Apr 7 23:23:35 1999
++++ telnet.obsd-cvs/main.c Sat Mar 10 09:59:35 2001
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: main.c,v 1.7 1998/05/15 03:16:38 art Exp $ */
++/* $OpenBSD: main.c,v 1.10 2001/01/21 22:46:37 aaron Exp $ */
+ /* $NetBSD: main.c,v 1.5 1996/02/28 21:04:05 thorpej Exp $ */
+
+ /*
+@@ -81,10 +81,10 @@
+ prompt,
+ #ifdef AUTHENTICATION
+ "[-8] [-E] [-K] [-L] [-S tos] [-X atype] [-a] [-c] [-d] [-e char]",
+- "\n\t[-k realm] [-l user] [-f/-F] [-n tracefile] [-b hostalias ]",
++ "\n\t[-k realm] [-l user] [-f/-F] [-n tracefile] [-b hostalias ] ",
+ #else
+ "[-8] [-E] [-L] [-S tos] [-a] [-c] [-d] [-e char] [-l user]",
+- "\n\t[-n tracefile] [-b hostalias ]",
++ "\n\t[-n tracefile] [-b hostalias ] ",
+ #endif
+ #if defined(TN3270) && defined(unix)
+ # ifdef AUTHENTICATION
+@@ -95,13 +95,11 @@
+ #else
+ "[-r] ",
+ #endif
++ "\n\r "
+ #ifdef ENCRYPTION
+- "[-x] [host-name [port]]"
+-#else
+-
+- "[host-name [port]]"
++ "[-x] "
+ #endif
+- );
++ "[host-name [port]]");
+ exit(1);
+ }
+
+@@ -276,8 +274,8 @@
+ break;
+ case 't':
+ #if defined(TN3270) && defined(unix)
++ (void)strncpy(tline, optarg, sizeof(tline));
+ transcom = tline;
+- (void)strcpy(transcom, optarg);
+ #else
+ fprintf(stderr,
+ "%s: Warning: -t ignored, no TN3270 support.\n",
+diff -uNr telnet/sys_bsd.c telnet.obsd-cvs/sys_bsd.c
+--- telnet/sys_bsd.c Wed Apr 7 21:38:31 1999
++++ telnet.obsd-cvs/sys_bsd.c Sat Mar 10 10:55:18 2001
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: sys_bsd.c,v 1.6 1998/12/28 11:13:51 deraadt Exp $ */
++/* $OpenBSD: sys_bsd.c,v 1.8 2000/10/10 15:41:10 millert Exp $ */
+ /* $NetBSD: sys_bsd.c,v 1.11 1996/02/28 21:04:10 thorpej Exp $ */
+
+ /*
+@@ -35,6 +35,7 @@
+ */
+
+ #include "telnet_locl.h"
++#include <err.h>
+
+ /*
+ * The following routines try to encapsulate what is system dependent
+@@ -198,9 +199,10 @@
+ TerminalFlushOutput(void)
+ {
+ #ifdef TIOCFLUSH
+- (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
++ int com = FWRITE;
++ (void) ioctl(fileno(stdout), TIOCFLUSH, (int *) &com);
+ #else
+- (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
++ (void) ioctl(fileno(stdout), TCFLSH, (int *) 0);
+ #endif
+ }
+
+diff -uNr telnet/telnet.c telnet.obsd-cvs/telnet.c
+--- telnet/telnet.c Wed Apr 7 23:22:14 1999
++++ telnet.obsd-cvs/telnet.c Sat Mar 10 11:02:34 2001
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: telnet.c,v 1.6 1998/07/27 15:29:29 millert Exp $ */
++/* $OpenBSD: telnet.c,v 1.11 2000/11/10 15:33:13 provos millert Exp $ */
+ /* $NetBSD: telnet.c,v 1.7 1996/02/28 21:04:15 thorpej Exp $ */
+
+ /*
+@@ -35,6 +35,8 @@
+ */
+
+ #include "telnet_locl.h"
++#include <curses.h>
++#include <term.h>
+
+ #define strip(x) (eight ? (x) : ((x) & 0x7f))
+
+@@ -523,10 +525,9 @@
+ }
+
+ /*
+- * Given a buffer returned by tgetent(), this routine will turn
+- * the pipe seperated list of names in the buffer into an array
+- * of pointers to null terminated names. We toss out any bad,
+- * duplicate, or verbose names (names with spaces).
++ * This routine will turn a pipe seperated list of names in the buffer
++ * into an array of pointers to NUL terminated names. We toss out any
++ * bad, duplicate, or verbose names (names with spaces).
+ */
+
+ int is_unique P((char *, char **, char **));
+@@ -554,7 +555,7 @@
+ /*
+ * Count up the number of names.
+ */
+- for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
++ for (n = 1, cp = buf; *cp; cp++) {
+ if (*cp == '|')
+ n++;
+ }
+@@ -659,25 +660,6 @@
+ return (1);
+ }
+
+-static char termbuf[1024];
+-
+-int telnet_setupterm P((char *tname, int fd, int *errp)); /* XXX move elsewhere */
+- /*ARGSUSED*/
+- int
+-telnet_setupterm(char *tname, int fd, int *errp)
+-{
+- (void)fd;
+- if (tgetent(termbuf, tname) == 1) {
+- termbuf[1023] = '\0';
+- if (errp)
+- *errp = 1;
+- return(0);
+- }
+- if (errp)
+- *errp = 0;
+- return(-1);
+-}
+-
+ int resettermname = 1;
+
+ char *gettermname P((void)); /* XXX move elsewhere */
+@@ -687,15 +669,15 @@
+ char *tname;
+ static char **tnamep = 0;
+ static char **next;
+- int err;
++ int errret;
+
+ if (resettermname) {
+ resettermname = 0;
+ if (tnamep && tnamep != unknown)
+ free(tnamep);
+ if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
+- (telnet_setupterm(tname, 1, &err) == 0)) {
+- tnamep = mklist(termbuf, tname);
++ (setupterm(tname, 1, &errret) == 0)) {
++ tnamep = mklist(ttytype, tname);
+ } else {
+ if (tname && ((int)strlen(tname) <= 40)) {
+ unknown[0] = tname;
+@@ -1482,10 +1464,15 @@
+ void
+ env_opt_start(void)
+ {
+- if (opt_reply)
+- opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
+- else
+- opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
++ unsigned char *p;
++
++ if (opt_reply) {
++ p = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
++ if (p == NULL)
++ free(opt_reply);
++ } else
++ p = (unsigned char *)malloc(OPT_REPLY_SIZE);
++ opt_reply = p;
+ if (opt_reply == NULL) {
+ /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
+ opt_reply = opt_replyp = opt_replyend = NULL;
+@@ -1532,9 +1519,13 @@
+ strlen((char *)ep) + 6 > opt_replyend)
+ {
+ int len;
++ unsigned char *p;
+ opt_replyend += OPT_REPLY_SIZE;
+ len = opt_replyend - opt_reply;
+- opt_reply = (unsigned char *)realloc(opt_reply, len);
++ p = (unsigned char *)realloc(opt_reply, len);
++ if (p == NULL)
++ free(opt_reply);
++ opt_reply = p;
+ if (opt_reply == NULL) {
+ /*@*/ printf("env_opt_add: realloc() failed!!!\n");
+ opt_reply = opt_replyp = opt_replyend = NULL;
+@@ -1945,7 +1936,7 @@
+ command(0, "z\n", 2);
+ continue;
+ }
+- if (sc == escape) {
++ if (sc == escape && escape != _POSIX_VDISABLE) {
+ command(0, (char *)tbp, tcc);
+ bol = 1;
+ count += tcc;
+@@ -1962,7 +1953,7 @@
+ }
+ if ((sc == '\n') || (sc == '\r'))
+ bol = 1;
+- } else if (sc == escape) {
++ } else if (sc == escape && escape != _POSIX_VDISABLE) {
+ /*
+ * Double escape is a pass through of a single escape character.
+ */
+diff -uNr telnet/telnet_locl.h telnet.obsd-cvs/telnet_locl.h
+--- telnet/telnet_locl.h Thu Mar 12 06:57:44 1998
++++ telnet.obsd-cvs/telnet_locl.h Sat Mar 10 11:12:37 2001
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: telnet_locl.h,v 1.1 1998/03/12 04:57:44 art Exp $ */
++/* $OpenBSD: telnet_locl.h,v 1.2 1999/12/11 09:08:09 itojun Exp $ */
+ /* $KTH: telnet_locl.h,v 1.13 1997/11/03 21:37:55 assar Exp $ */
+
+ /*
+@@ -86,7 +86,5 @@
+ #include "defines.h"
+ #include "types.h"
+
+-#undef AF_INET6 /* XXX - it has not been tested and it doesn't exist yet */
+-
+ /* prototypes */
+
+diff -uNr libtelnet/kerberos.c libtelnet.obsd-cvs/kerberos.c
+--- libtelnet/kerberos.c Mon Feb 8 23:38:17 1999
++++ libtelnet.obsd-cvs/kerberos.c Sat Mar 10 11:11:03 2001
+@@ -320,11 +320,10 @@
+ char ts[MAXPATHLEN];
+ struct passwd *pw = getpwnam(UserNameRequested);
+
+- if(pw){
++ if (pw) {
+ snprintf(ts, sizeof(ts),
+- "%s%u",
+- TKT_ROOT,
+- (unsigned)pw->pw_uid);
++ "%s%u", TKT_ROOT, (unsigned)pw->pw_uid);
++ /* XXX allocation failure? */
+ setenv("KRBTKFILE", ts, 1);
+ }
+ Data(ap, KRB_ACCEPT, NULL, 0);
+@@ -609,16 +608,26 @@
+ {
+ unsigned char *p = buf;
+
+- p += krb_put_nir(cred->service, cred->instance, cred->realm, p);
++ memcpy (p, cred->service, ANAME_SZ);
++ p += ANAME_SZ;
++ memcpy (p, cred->instance, INST_SZ);
++ p += INST_SZ;
++ memcpy (p, cred->realm, REALM_SZ);
++ p += REALM_SZ;
+ memcpy(p, cred->session, 8);
+ p += 8;
+ *p++ = cred->lifetime;
+ *p++ = cred->kvno;
+- p += krb_put_int(cred->ticket_st.length, p, 4);
++ p += krb_put_int(cred->ticket_st.length, p, 4, 4);
+ memcpy(p, cred->ticket_st.dat, cred->ticket_st.length);
+ p += cred->ticket_st.length;
+- p += krb_put_int(cred->issue_date, p, 4);
+- p += krb_put_nir(cred->pname, cred->pinst, NULL, p);
++ p += krb_put_int(cred->issue_date, p, 4, 4);
++ strncpy (cred->pname, p, ANAME_SZ);
++ cred->pname[ANAME_SZ - 1] = '\0';
++ p += ANAME_SZ;
++ strncpy (cred->pinst, p, INST_SZ);
++ cred->pinst[INST_SZ - 1] = '\0';
++ p += INST_SZ;
+ return p - buf;
+ }
+
+@@ -627,7 +636,16 @@
+ {
+ unsigned char *p = buf;
+
+- p += krb_get_nir(p, cred->service, cred->instance, cred->realm);
++ strncpy (cred->service, p, ANAME_SZ);
++ cred->service[ANAME_SZ - 1] = '\0';
++ p += ANAME_SZ;
++ strncpy (cred->instance, p, INST_SZ);
++ cred->instance[INST_SZ - 1] = '\0';
++ p += INST_SZ;
++ strncpy (cred->realm, p, REALM_SZ);
++ cred->realm[REALM_SZ - 1] = '\0';
++ p += REALM_SZ;
++
+ memcpy(cred->session, p, 8);
+ p += 8;
+ cred->lifetime = *p++;
+@@ -636,7 +654,10 @@
+ memcpy(cred->ticket_st.dat, p, cred->ticket_st.length);
+ cred->ticket_st.mbz = 0;
+ p += krb_get_int(p, (u_int32_t *)&cred->issue_date, 4, 0);
+- p += krb_get_nir(p, cred->pname, cred->pinst, NULL);
++ p += krb_get_nir(p,
++ cred->pname, sizeof(cred->pname),
++ cred->pinst, sizeof(cred->pinst),
++ NULL, 0);
+ return 0;
+ }
+
+--- telnet/telnet.1 Thu Nov 12 01:01:46 1998
++++ telnet.obsd-cvs/telnet.1 Thu Nov 9 19:52:41 2000
+@@ -1,4 +1,4 @@
+-.\" $OpenBSD: telnet.1,v 1.14 1998/11/11 23:01:46 aaron Exp $
++.\" $OpenBSD: telnet.1,v 1.27 2000/11/09 17:52:41 aaron Exp $
+ .\" $NetBSD: telnet.1,v 1.5 1996/02/28 21:04:12 thorpej Exp $
+ .\"
+ .\" Copyright (c) 1983, 1990, 1993
+@@ -36,45 +36,34 @@
+ .\"
+ .Dd February 3, 1994
+ .Dt TELNET 1
+-.Os BSD 4.2
++.Os
+ .Sh NAME
+ .Nm telnet
+-.Nd user interface to the
++.Nd user interface to the
+ .Tn TELNET
+ protocol
+ .Sh SYNOPSIS
+ .Nm telnet
+-.Op Fl 8
+-.Op Fl E
+-.Op Fl F
+-.Op Fl K
+-.Op Fl L
+-.Op Fl S Ar tos
++.Op Fl 8EFKLacdfrx
+ .Op Fl X Ar authtype
+-.Op Fl a
+ .Op Fl b Ar hostalias
+-.Op Fl c
+-.Op Fl d
+ .Op Fl e Ar escapechar
+-.Op Fl f
+ .Op Fl k Ar realm
+ .Op Fl l Ar user
+ .Op Fl n Ar tracefile
+-.Op Fl r
+-.Op Fl x
+ .Oo
+ .Ar host
+ .Op Ar port
+ .Oc
+ .Sh DESCRIPTION
+ The
+-.Nm telnet
++.Nm
+ command
+-is used to communicate with another host using the
++is used to communicate with another host using the
+ .Tn TELNET
+ protocol.
+ If
+-.Nm telnet
++.Nm
+ is invoked without the
+ .Ar host
+ argument, it enters command mode,
+@@ -85,11 +74,11 @@
+ .Ic open
+ command with those arguments.
+ .Pp
+-Options:
+-.Bl -tag -width indent
++The options are as follows:
++.Bl -tag -width Ds
+ .It Fl 8
+-Specifies an 8-bit data path. This causes an attempt to
+-negotiate the
++Specifies an 8-bit data path.
++This causes an attempt to negotiate the
+ .Dv TELNET BINARY
+ option on both input and output.
+ .It Fl E
+@@ -103,18 +92,9 @@
+ .It Fl K
+ Specifies no automatic login to the remote system.
+ .It Fl L
+-Specifies an 8-bit data path on output. This causes the
+-BINARY option to be negotiated on output.
+-.It Fl S Ar tos
+-Sets the IP type-of-service (TOS) option for the telnet
+-connection to the value
+-.Ar tos ,
+-which can be a numeric TOS value
+-or, on systems that support it, a symbolic
+-TOS name found in the
+-.Pa /etc/iptos
+-file.
+-.It Fl X Ar atype
++Specifies an 8-bit data path on output.
++This causes the BINARY option to be negotiated on output.
++.It Fl X Ar atype
+ Disables the
+ .Ar atype
+ type of authentication.
+@@ -144,7 +124,8 @@
+ .It Fl c
+ Disables the reading of the user's
+ .Pa \&.telnetrc
+-file. (See the
++file.
++(See the
+ .Ic toggle skiprc
+ command on this man page.)
+ .It Fl d
+@@ -152,7 +133,7 @@
+ .Ic debug
+ toggle to
+ .Dv TRUE .
+-.It Fl e Ar escapechar
++.It Fl e Ar escapechar
+ Sets the initial
+ .Nm
+ escape character to
+@@ -169,14 +150,14 @@
+ If Kerberos authentication is being used, the
+ .Fl k
+ option requests that
+-.Nm telnet
++.Nm
+ obtain tickets for the remote host in
+ realm
+ .Ar realm
+ instead of the remote host's realm, as determined
+ by
+ .Xr krb_realmofhost 3 .
+-.It Fl l Ar user
++.It Fl l Ar user
+ When connecting to the remote system, if the remote system
+ understands the
+ .Ev ENVIRON
+@@ -189,7 +170,7 @@
+ This option may also be used with the
+ .Ic open
+ command.
+-.It Fl n Ar tracefile
++.It Fl n Ar tracefile
+ Opens
+ .Ar tracefile
+ for recording trace information.
+@@ -210,35 +191,38 @@
+ Indicates the official name, an alias, or the Internet address
+ of a remote host.
+ .It Ar port
+-Indicates a port number (address of an application). If a number is
+-not specified, the default
+-.Nm telnet
++Indicates a port number (address of an application).
++If a number is not specified, the default
++.Nm
+ port is used.
+ .El
+ .Pp
+-When in rlogin mode, a line of the form ~. disconnects from the
++When in rlogin mode, a line of the form ~.
++disconnects from the
+ remote host; ~ is the telnet escape character.
+ Similarly, the line ~^Z suspends the telnet session.
+ The line ~^] escapes to the normal telnet escape prompt.
+ .Pp
+ Once a connection has been opened,
+-.Nm telnet
++.Nm
+ will attempt to enable the
+ .Dv TELNET LINEMODE
+ option.
+ If this fails,
+-.Nm telnet
++.Nm
+ will revert to one of two input modes:
+ either ``character at a time''
+ or ``old line by line''
+ depending on what the remote system supports.
+ .Pp
+-When
++When
+ .Dv LINEMODE
+ is enabled, character processing is done on the
+-local system, under the control of the remote system. When input
++local system, under the control of the remote system.
++When input
+ editing or character echoing is to be disabled, the remote system
+-will relay that information. The remote system will also relay
++will relay that information.
++The remote system will also relay
+ changes to any special characters that happen on the remote
+ system, so that they can take effect on the local system.
+ .Pp
+@@ -252,7 +236,7 @@
+ (this would mostly be used to enter passwords
+ without the password being echoed).
+ .Pp
+-If the
++If the
+ .Dv LINEMODE
+ option is enabled, or if the
+ .Ic localchars
+@@ -267,7 +251,7 @@
+ characters are trapped locally, and sent as
+ .Tn TELNET
+ protocol sequences to the remote side.
+-If
++If
+ .Dv LINEMODE
+ has ever been enabled, then the user's
+ .Ic susp
+@@ -278,9 +262,9 @@
+ protocol sequences,
+ and
+ .Ic quit
+-is sent as a
++is sent as a
+ .Dv TELNET ABORT
+-instead of
++instead of
+ .Dv BREAK .
+ There are options (see
+ .Ic toggle
+@@ -296,17 +280,26 @@
+ (in the case of
+ .Ic quit
+ and
+-.Ic intr ) .
++.Ic intr ) .
+ .Pp
+ While connected to a remote host,
+-.Nm telnet
++.Nm
+ command mode may be entered by typing the
+-.Nm telnet
++.Nm
+ ``escape character'' (initially ``^]'').
+ When in command mode, the normal terminal editing conventions are available.
++Note that the escape character will return to the command mode of the initial
++invocation of
++.Nm
++that has the controlling terminal.
++Use the
++.Cm send escape
++command to switch to command mode in subsequent
++.Nm
++processes on remote hosts.
+ .Pp
+ The following
+-.Nm telnet
++.Nm
+ commands are available.
+ Only enough of each command to uniquely identify it need be typed
+ (this is also true for arguments to the
+@@ -320,26 +313,28 @@
+ .Ic display
+ commands).
+ .Bl -tag -width "mode type"
+-.It Ic auth Ar argument Op Ar ...
++.It Ic auth Ar argument Op Ar ...
+ The
+ .Ic auth
+ command manipulates the information sent through the
+ .Dv TELNET AUTHENTICATE
+-option. Valid arguments for the
+-auth command are as follows:
++option.
++Valid arguments for the
++.Ic auth
++command are as follows:
+ .Bl -tag -width "disable type"
+ .It Ic disable Ar type
+ Disables the specified
+ .Ar type
+-of authentication. To
+-obtain a list of available types, use the
++of authentication.
++To obtain a list of available types, use the
+ .Ic auth disable \&?
+ command.
+ .It Ic enable Ar type
+ Enables the specified
+ .Ar type
+-of authentication. To
+-obtain a list of available types, use the
++of authentication.
++To obtain a list of available types, use the
+ .Ic auth enable \&?
+ command.
+ .It Ic status
+@@ -350,7 +345,7 @@
+ Close a
+ .Tn TELNET
+ session and return to command mode.
+-.It Ic display Ar argument Op Ar ...
++.It Ic display Ar argument Op Ar ...
+ Displays all, or some, of the
+ .Ic set
+ and
+@@ -368,26 +363,27 @@
+ .It Ic disable Ar type Ic [input|output]
+ Disables the specified
+ .Ar type
+-of encryption. If you
+-omit
++of encryption.
++If you omit
+ .Ic input
+ and
+ .Ic output ,
+ both input and output
+-are disabled. To obtain a list of available
+-types, use the
++are disabled.
++To obtain a list of available types, use the
+ .Ic encrypt disable \&?
+ command.
+ .It Ic enable Ar type Ic [input|output]
+ Enables the specified
+ .Ar type
+-of encryption. If you
+-omit
++of encryption.
++If you omit
+ .Ic input
+ and
+ .Ic output ,
+ both input and output are
+-enabled. To obtain a list of available types, use the
++enabled.
++To obtain a list of available types, use the
+ .Ic encrypt enable \&?
+ command.
+ .It Ic input
+@@ -407,18 +403,20 @@
+ .Ic encrypt stop output
+ command.
+ .It Ic start Ic [input|output]
+-Attempts to start encryption. If you omit
++Attempts to start encryption.
++If you omit
+ .Ic input
+ and
+-.Ic output,
+-both input and output are enabled. To
+-obtain a list of available types, use the
++.Ic output ,
++both input and output are enabled.
++To obtain a list of available types, use the
+ .Ic encrypt enable \&?
+ command.
+ .It Ic status
+ Lists the current status of encryption.
+ .It Ic stop Ic [input|output]
+-Stops encryption. If you omit
++Stops encryption.
++If you omit
+ .Ic input
+ and
+ .Ic output ,
+@@ -431,7 +429,7 @@
+ .Ic encrypt stop
+ commands.
+ .El
+-.It Ic environ Ar arguments Op Ar ...
++.It Ic environ Ar arguments Op Ar ...
+ The
+ .Ic environ
+ command is used to manipulate the
+@@ -456,7 +454,7 @@
+ .Ic environ
+ command are:
+ .Bl -tag -width Fl
+-.It Ic define Ar variable value
++.It Ic define Ar variable value
+ Define the variable
+ .Ar variable
+ to have a value of
+@@ -466,15 +464,15 @@
+ .Ar value
+ may be enclosed in single or double quotes so
+ that tabs and spaces may be included.
+-.It Ic undefine Ar variable
++.It Ic undefine Ar variable
+ Remove
+ .Ar variable
+ from the list of environment variables.
+-.It Ic export Ar variable
++.It Ic export Ar variable
+ Mark the variable
+ .Ar variable
+ to be exported to the remote side.
+-.It Ic unexport Ar variable
++.It Ic unexport Ar variable
+ Mark the variable
+ .Ar variable
+ to not be exported unless
+@@ -508,7 +506,7 @@
+ suspending a user's session for later reattachment,
+ the logout argument indicates that you
+ should terminate the session immediately.
+-.It Ic mode Ar type
++.It Ic mode Ar type
+ .Ar type
+ is one of several options, depending on the state of the
+ .Tn TELNET
+@@ -529,40 +527,40 @@
+ option, or, if the remote side does not understand the
+ .Dv LINEMODE
+ option, then attempt to enter ``old-line-by-line'' mode.
+-.It Ic isig Pq Ic \-isig
+-Attempt to enable (disable) the
++.It Ic isig Pq Ic \-isig
++Attempt to enable (disable) the
+ .Dv TRAPSIG
+-mode of the
++mode of the
+ .Dv LINEMODE
+ option.
+-This requires that the
++This requires that the
+ .Dv LINEMODE
+ option be enabled.
+-.It Ic edit Pq Ic \-edit
+-Attempt to enable (disable) the
++.It Ic edit Pq Ic \-edit
++Attempt to enable (disable) the
+ .Dv EDIT
+-mode of the
++mode of the
+ .Dv LINEMODE
+ option.
+-This requires that the
++This requires that the
+ .Dv LINEMODE
+ option be enabled.
+-.It Ic softtabs Pq Ic \-softtabs
+-Attempt to enable (disable) the
++.It Ic softtabs Pq Ic \-softtabs
++Attempt to enable (disable) the
+ .Dv SOFT_TAB
+-mode of the
++mode of the
+ .Dv LINEMODE
+ option.
+-This requires that the
++This requires that the
+ .Dv LINEMODE
+ option be enabled.
+-.It Ic litecho Pq Ic \-litecho
+-Attempt to enable (disable) the
++.It Ic litecho Pq Ic \-litecho
++Attempt to enable (disable) the
+ .Dv LIT_ECHO
+-mode of the
++mode of the
+ .Dv LINEMODE
+ option.
+-This requires that the
++This requires that the
+ .Dv LINEMODE
+ option be enabled.
+ .It Ic \&?
+@@ -579,7 +577,7 @@
+ Open a connection to the named host.
+ If no port number
+ is specified,
+-.Nm telnet
++.Nm
+ will attempt to contact a
+ .Tn TELNET
+ server at the default port.
+@@ -594,24 +592,29 @@
+ .Ev ENVIRON
+ option.
+ When connecting to a non-standard port,
+-.Nm telnet
++.Nm
+ omits any automatic initiation of
+ .Tn TELNET
+-options. When the port number is preceded by a minus sign,
++options.
++When the port number is preceded by a minus sign,
+ the initial option negotiation is done.
+ After establishing a connection, the file
+ .Pa \&.telnetrc
+ in the
+-user's home directory is opened. Lines beginning with a ``#'' are
+-comment lines. Blank lines are ignored. Lines that begin
+-without white space are the start of a machine entry. The
+-first thing on the line is the name of the machine that is
+-being connected to. The rest of the line, and successive
+-lines that begin with white space are assumed to be
+-.Nm telnet
++user's home directory is opened.
++Lines beginning with a ``#'' are
++comment lines.
++Blank lines are ignored.
++Lines that begin
++without whitespace are the start of a machine entry.
++The first thing on the line is the name of the machine that is
++being connected to.
++The rest of the line, and successive
++lines that begin with whitespace are assumed to be
++.Nm
+ commands and are processed as if they had been typed
+ in manually to the
+-.Nm telnet
++.Nm
+ command prompt.
+ .It Ic quit
+ Close any open
+@@ -619,7 +622,7 @@
+ session and exit
+ .Nm telnet .
+ An end-of-file (in command mode) will also close a session and exit.
+-.It Ic send Ar arguments
++.It Ic send Ar arguments
+ Sends one or more special character sequences to the remote host.
+ The following are the arguments which may be specified
+ (more than one argument may be specified at a time):
+@@ -673,7 +676,7 @@
+ sequence.
+ .It Ic escape
+ Sends the current
+-.Nm telnet
++.Nm
+ escape character (initially ``^]'').
+ .It Ic ga
+ Sends the
+@@ -788,12 +791,12 @@
+ .Ic send
+ command.
+ .El
+-.It Ic set Ar argument value
+-.It Ic unset Ar argument value
++.It Ic set Ar argument value
++.It Ic unset Ar argument value
+ The
+ .Ic set
+ command will set any one of a number of
+-.Nm telnet
++.Nm
+ variables to a specific value or to
+ .Dv TRUE .
+ The special value
+@@ -811,7 +814,8 @@
+ .Ic display
+ command.
+ The variables which may be set or unset, but not toggled, are
+-listed here. In addition, any of the variables for the
++listed here.
++In addition, any of the variables for the
+ .Ic toggle
+ command may be explicitly set or unset using
+ the
+@@ -832,7 +836,8 @@
+ sequence (see
+ .Ic send ayt
+ preceding) is sent to the
+-remote host. The initial value for the "Are You There"
++remote host.
++The initial value for the "Are You There"
+ character is the terminal's status character.
+ .It Ic echo
+ This is the value (initially ``^E'') which, when in
+@@ -841,7 +846,7 @@
+ echoing of entered characters (for entering, say, a password).
+ .It Ic eof
+ If
+-.Nm telnet
++.Nm
+ is operating in
+ .Dv LINEMODE
+ or ``old line by line'' mode, entering this character
+@@ -854,7 +859,7 @@
+ character.
+ .It Ic erase
+ If
+-.Nm telnet
++.Nm
+ is in
+ .Ic localchars
+ mode (see
+@@ -862,7 +867,7 @@
+ .Ic localchars
+ below),
+ and if
+-.Nm telnet
++.Nm
+ is operating in ``character at a time'' mode, then when this
+ character is typed, a
+ .Dv TELNET EC
+@@ -879,14 +884,14 @@
+ character.
+ .It Ic escape
+ This is the
+-.Nm telnet
++.Nm
+ escape character (initially ``^['') which causes entry
+ into
+-.Nm telnet
++.Nm
+ command mode (when connected to a remote system).
+ .It Ic flushoutput
+ If
+-.Nm telnet
++.Nm
+ is in
+ .Ic localchars
+ mode (see
+@@ -916,12 +921,13 @@
+ .Dv LINEMODE ,
+ these are the
+ characters that, when typed, cause partial lines to be
+-forwarded to the remote system. The initial value for
++forwarded to the remote system.
++The initial value for
+ the forwarding characters are taken from the terminal's
+ eol and eol2 characters.
+ .It Ic interrupt
+ If
+-.Nm telnet
++.Nm
+ is in
+ .Ic localchars
+ mode (see
+@@ -945,7 +951,7 @@
+ character.
+ .It Ic kill
+ If
+-.Nm telnet
++.Nm
+ is in
+ .Ic localchars
+ mode (see
+@@ -953,7 +959,7 @@
+ .Ic localchars
+ below),
+ and if
+-.Nm telnet
++.Nm
+ is operating in ``character at a time'' mode, then when this
+ character is typed, a
+ .Dv TELNET EL
+@@ -970,7 +976,7 @@
+ character.
+ .It Ic lnext
+ If
+-.Nm telnet
++.Nm
+ is operating in
+ .Dv LINEMODE
+ or ``old line by line'' mode, then this character is taken to
+@@ -985,7 +991,7 @@
+ character.
+ .It Ic quit
+ If
+-.Nm telnet
++.Nm
+ is in
+ .Ic localchars
+ mode (see
+@@ -1009,7 +1015,7 @@
+ character.
+ .It Ic reprint
+ If
+-.Nm telnet
++.Nm
+ is operating in
+ .Dv LINEMODE
+ or old line by line'' mode, then this character is taken to
+@@ -1031,8 +1037,9 @@
+ This character, at the beginning of a line, followed by
+ a "." closes the connection; when followed by a ^Z it
+ suspends the
+-.Nm telnet
+-command. The initial state is to
++.Nm
++command.
++The initial state is to
+ disable the
+ .Ic rlogin
+ escape character.
+@@ -1066,7 +1073,7 @@
+ character.
+ .It Ic susp
+ If
+-.Nm telnet
++.Nm
+ is in
+ .Ic localchars
+ mode, or
+@@ -1093,12 +1100,13 @@
+ .Ic option
+ tracing being
+ .Dv TRUE ,
+-will be written. If it is set to
++will be written.
++If it is set to
+ .Dq Fl ,
+ then tracing information will be written to standard output (the default).
+ .It Ic worderase
+ If
+-.Nm telnet
++.Nm
+ is operating in
+ .Dv LINEMODE
+ or ``old line by line'' mode, then this character is taken to
+@@ -1117,25 +1125,32 @@
+ .Pq Ic unset
+ commands.
+ .El
+-.It Ic slc Ar state
++.It Ic skey Ar sequence challenge
++The
++.Ic skey
++command computes a response to the S/Key challenge.
++See
++.Xr skey 1
++for more information on the S/Key system.
++.It Ic slc Ar state
+ The
+ .Ic slc
+ command (Set Local Characters) is used to set
+ or change the state of the special
+-characters when the
++characters when the
+ .Dv TELNET LINEMODE
+ option has
+-been enabled. Special characters are characters that get
+-mapped to
++been enabled.
++Special characters are characters that get mapped to
+ .Tn TELNET
+ commands sequences (like
+ .Ic ip
+ or
+-.Ic quit )
++.Ic quit )
+ or line editing characters (like
+ .Ic erase
+ and
+-.Ic kill ) .
++.Ic kill ) .
+ By default, the local special characters are exported.
+ .Bl -tag -width Fl
+ .It Ic check
+@@ -1144,15 +1159,15 @@
+ character settings, and if there are any discrepancies with
+ the local side, the local side will switch to the remote value.
+ .It Ic export
+-Switch to the local defaults for the special characters. The
+-local default characters are those of the local terminal at
++Switch to the local defaults for the special characters.
++The local default characters are those of the local terminal at
+ the time when
+-.Nm telnet
++.Nm
+ was started.
+ .It Ic import
+ Switch to the remote defaults for the special characters.
+ The remote default characters are those of the remote system
+-at the time when the
++at the time when the
+ .Tn TELNET
+ connection was established.
+ .It Ic \&?
+@@ -1165,13 +1180,13 @@
+ .Nm telnet .
+ This includes the peer one is connected to, as well
+ as the current mode.
+-.It Ic toggle Ar arguments Op Ar ...
++.It Ic toggle Ar arguments Op Ar ...
+ Toggle (between
+ .Dv TRUE
+ and
+ .Dv FALSE )
+ various flags that control how
+-.Nm telnet
++.Nm
+ responds to events.
+ These flags may be set explicitly to
+ .Dv TRUE
+@@ -1206,7 +1221,7 @@
+ sequences; see
+ .Ic set
+ above for details),
+-.Nm telnet
++.Nm
+ refuses to display any data on the user's terminal
+ until the remote system acknowledges (via a
+ .Dv TELNET TIMING MARK
+@@ -1220,13 +1235,14 @@
+ done an "stty noflsh", otherwise
+ .Dv FALSE
+ (see
+-.Xr stty 1 ) .
++.Xr stty 1 ) .
+ .It Ic autodecrypt
+ When the
+ .Dv TELNET ENCRYPT
+ option is negotiated, by
+ default the actual encryption (decryption) of the data
+-stream does not start automatically. The
++stream does not start automatically.
++The
+ .Ic autoencrypt
+ .Pq Ic autodecrypt
+ command states that encryption of the
+@@ -1238,7 +1254,8 @@
+ .Dv TELNET AUTHENTICATION
+ option
+ .Tn TELNET
+-attempts to use it to perform automatic authentication. If the
++attempts to use it to perform automatic authentication.
++If the
+ .Dv AUTHENTICATION
+ option is not supported, the user's login
+ name are propagated through the
+@@ -1314,7 +1331,7 @@
+ The initial value for this toggle is
+ .Dv FALSE .
+ .It Ic debug
+-Toggles socket level debugging (useful only to the super-user).
++Toggles socket level debugging (useful only to the superuser).
+ The initial value for this toggle is
+ .Dv FALSE .
+ .It Ic encdebug
+@@ -1340,7 +1357,7 @@
+ .Ic brk ,
+ .Ic ec ,
+ and
+-.Ic el ;
++.Ic el ;
+ see
+ .Ic send
+ above).
+@@ -1379,7 +1396,7 @@
+ .Dv FALSE .
+ .It Ic options
+ Toggles the display of some internal
+-.Nm telnet
++.Nm
+ protocol processing (having to do with
+ .Tn TELNET
+ options).
+@@ -1404,8 +1421,8 @@
+ skips the reading of the
+ .Pa \&.telnetrc
+ file in the user's home
+-directory when connections are opened. The initial
+-value for this toggle is
++directory when connections are opened.
++The initial value for this toggle is
+ .Dv FALSE .
+ .It Ic termdata
+ Toggles the display of all terminal data (in hexadecimal format).
+@@ -1416,9 +1433,10 @@
+ .Ic verbose_encrypt
+ toggle is
+ .Dv TRUE ,
+-.Nm telnet
++.Nm
+ prints out a message each time encryption is enabled or
+-disabled. The initial value for this toggle is
++disabled.
++The initial value for this toggle is
+ .Dv FALSE .
+ .It Ic \&?
+ Displays the legal
+@@ -1430,22 +1448,24 @@
+ .Nm telnet .
+ This command only works when the user is using the
+ .Xr csh 1 .
+-.It Ic \&! Op Ar command
++.It Ic \&! Op Ar command
+ Execute a single command in a subshell on the local
+-system. If
++system.
++If
+ .Ar command
+ is omitted, then an interactive
+ subshell is invoked.
+-.It Ic \&? Op Ar command
+-Get help. With no arguments,
+-.Nm telnet
++.It Ic \&? Op Ar command
++Get help.
++With no arguments,
++.Nm
+ prints a help summary.
+ If a command is specified,
+-.Nm telnet
++.Nm
+ will print the help information for just that command.
+ .El
+ .Sh ENVIRONMENT
+-.Nm telnet
++.Nm
+ uses at least the
+ .Ev HOME ,
+ .Ev SHELL ,
+@@ -1464,16 +1484,18 @@
+ .El
+ .Sh HISTORY
+ The
+-.Nm telnet
++.Nm
+ command appeared in
+ .Bx 4.2 .
+ .Sh NOTES
+ On some remote systems, echo has to be turned off manually when in
+ ``old line by line'' mode.
+ .Pp
+-In ``old line by line'' mode or
++In ``old line by line'' mode or
+ .Dv LINEMODE
+ the terminal's
+ .Ic eof
+ character is only recognized (and sent to the remote system)
+ when it is the first character on a line.
++.Pp
++Source routing is not supported yet for IPv6.
--- /dev/null
+--- netkit-telnet-0.17/telnet/commands.c.old 2006-04-30 10:24:49.000000000 -0700
++++ netkit-telnet-0.17/telnet/commands.c 2006-04-30 10:37:10.000000000 -0700
+@@ -1669,9 +1669,15 @@
+
+ /* If this is not the full name, try to get it via DNS */
+ if (strchr(hbuf, '.') == 0) {
+- struct hostent *he = gethostbyname(hbuf);
+- if (he != 0)
+- strncpy(hbuf, he->h_name, sizeof hbuf-1);
++ struct addrinfo hints;
++ struct addrinfo *res;
++ memset (&hints, '\0', sizeof (hints));
++ hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME;
++ if (getaddrinfo (hbuf, NULL, &hints, &res) == 0) {
++ if (res->ai_canonname != NULL)
++ strncpy(hbuf, res->ai_canonname, sizeof hbuf-1);
++ freeaddrinfo (res);
++ }
+ hbuf[sizeof hbuf-1] = '\0';
+ }
+
+@@ -2832,17 +2838,15 @@
+ if (!c)
+ cp2 = 0;
+
+- if ((tmp = inet_addr(cp)) != -1) {
+- sin_addr.s_addr = tmp;
+- } else if ((host = gethostbyname(cp))) {
+-#if defined(h_addr)
+- memmove((caddr_t)&sin_addr,
+- host->h_addr_list[0],
+- sizeof(sin_addr));
+-#else
+- memmove((caddr_t)&sin_addr, host->h_addr,
+- sizeof(sin_addr));
+-#endif
++ struct addrinfo hints;
++ memset (&hints, '\0', sizeof (hints));
++ // XXX The code here seems to allow only IPv4 addresses.
++ hints.ai_family = AF_INET;
++ hints.ai_flags = AI_ADDRCONFIG;
++ struct addrinfo *aires;
++ if (getaddrinfo (cp, NULL, &hints, &aires) == 0) {
++ sin_addr = ((struct sockaddr_in *) aires->ai_addr)->sin_addr;
++ freeaddrinfo (aires);
+ } else {
+ *cpp = cp;
+ return(0);