diff --git a/contrib/isc-dhcp/FREEBSD-upgrade b/contrib/isc-dhcp/FREEBSD-upgrade index 0f8f8ef16d71..aa7c51724a3b 100644 --- a/contrib/isc-dhcp/FREEBSD-upgrade +++ b/contrib/isc-dhcp/FREEBSD-upgrade @@ -1,45 +1,44 @@ # ex:ts=8 $FreeBSD$ ISC DHCP client 2.0 originals can be found at: ftp://ftp.isc.org/isc/dhcp/ For the import of ISC-dhclient the following files were removed: - Makefile.conf Makefile.dist configure doc*/* relay/* server/* client/ - Makefile.dist dhclient-script.cat8 dhclient.cat8 + dhclient-script.cat8 dhclient.cat8 dhclient.conf.cat5 dhclient.leases.cat5 client/scripts/ bsdos linux netbsd nextstep solaris common/ - Makefile.dist dhcp-options.cat5 dlpi.c + dhcp-options.cat5 dlpi.c include/cf/ aix.h alphaosf.h bsdos.h cygwin32.h hpux.h irix.h linux.h netbsd.h nextstep.h qnx.h rhapsody.h sample.h sco.h sunos4.h sunos5-5.h ultrix.h Imported by: - cvs import -m 'Virgin import of ISC-DHCP v2.0' \ - src/contrib/isc-dhcp ISC isc_dhcp_2_0 + cvs import -m 'Import Patchlevel 3 of the ISC 2.0 dhcp client.' \ + src/contrib/isc-dhcp ISC isc_dhcp_2_0_pl3 To make local changes to isc-dhcp, simply patch and commit to the main branch (aka HEAD). Never make local changes on the vendor (ISC) branch. All local changes should be submitted to the ISC for inclusion in the next vendor release. obrien@NUXI.com -23-June-1999 +20-July-2000 diff --git a/contrib/isc-dhcp/Makefile.conf b/contrib/isc-dhcp/Makefile.conf index d2fb53499fc5..509e32f823a3 100644 --- a/contrib/isc-dhcp/Makefile.conf +++ b/contrib/isc-dhcp/Makefile.conf @@ -1,332 +1,333 @@ # Makefile.conf # # Copyright (c) 1996, 1997, 1998, 1999 The Internet Software Consortium. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of The Internet Software Consortium nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND # CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL # THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # ## Defaults... SCRIPT = none BINDIR = /usr/sbin CLIENTBINDIR=/sbin ADMMANEXT = .0 FFMANEXT = .0 ADMMANDIR = /usr/share/man/cat8 FFMANDIR = /usr/share/man/cat5 INSTALL = install -c MANINSTALL = install -c -m 444 CHMOD = chmod CATMANPAGES = MANCAT = cat ETC = /etc VARRUN = /var/run VARDB = /var/db +CLIENT_PATH = '"PATH=/usr/ucb:/usr/bin:/usr/sbin:/bin:/sbin"' # Major version number (if applicable) ##--majver-- MAJORVERSION=MajorVersion ##--majver-- # Minor version number (if applicable) ##--minver-- MINORVERSION=MinorVersion ##--minver-- ## Porting:: # # For each supported operating system, there is a block of text below # beginning with #--os-name-- and ending with #--os-name--. Between # these delimiters are assignments, commented out, which define the # Makefile variables required for that operating system. # # The configure shell script figures out what operating system it's # being run on and then runs Makefile.dist through a sed script which # removes the comment characters from the appropriate set of # assignments, and writes the output to Makefile. ## AIX 4.1.5.0 ##--aix-- #CF = cf/aix.h #CC=cc -Daix #INSTALL=/usr/ucb/install #MANINSTALL=/usr/ucb/install #ADMMANEXT = .8 #FFMANEXT = .5 #VARRUN = /etc #VARDB = /etc ##--aix-- ## NEXTSTEP 3.x,4.x ##--nextstep-- #LIBS = #CF = cf/nextstep.h #CC=cc #COPTS = -Wall #BINDIR=/usr/etc #ADMMANDIR = /usr/local/man/cat8 #FFMANDIR = /usr/local/man/cat5 #ADMMANEXT = .8 #FFMANEXT = .5 #VARRUN = /etc #VARDB = /etc ##--nextstep-- ## SunOS 4.1 ##--sunos4-- #LIBS = -lresolv #CF = cf/sunos4.h #BINDIR=/usr/etc #CLIENTBINDIR=/etc #ADMMANEXT = .8 #FFMANEXT = .5 #VARRUN = /etc #VARDB = /etc ##--sunos4-- ## Solaris 2.5 (with gcc) ##--sunos5-gcc-- #INSTALL=/usr/ucb/install #MANINSTALL=/usr/ucb/install #LIBS = -lresolv -lsocket -lnsl -lgen #CC=gcc #COPTS = -Wall -Wno-unused -Wno-implicit -Wno-comment \ # -Wno-uninitialized -Wno-char-subscripts -Werror #CF = cf/sunos5-5.h #ADMMANDIR = /usr/share/man/cat1m #ADMMANEXT = .1m #FFMANDIR = /usr/share/man/cat4 #FFMANEXT = .4 #VARRUN = /etc #VARDB = /etc #SCRIPT=solaris ##--sunos5-gcc-- ## Solaris 2.5 (with Sun cc) ##--sunos5-cc-- #INSTALL=/usr/ucb/install #MANINSTALL=/usr/ucb/install #LIBS = -lresolv -lsocket -lnsl -lgen #CC=cc #COPTS = -D__svr4__ #CF = cf/sunos5-5.h #ADMMANDIR = /usr/share/man/cat1m #ADMMANEXT = .1m #FFMANDIR = /usr/share/man/cat4 #FFMANEXT = .4 #VARRUN = /etc #VARDB = /etc #SCRIPT=solaris ##--sunos5-cc-- ## DEC Alpha/OSF1 ##--alphaosf-- #CC=cc -std0 #INSTALL=/usr/ucb/installbsd #MANINSTALL=/usr/ucb/installbsd #LIBS= #CF = cf/alphaosf.h #ADMMANEXT = .8 #FFMANEXT = .5 #VARDB = /etc ##--alphaosf-- ## BSD/OS 2.1 ##--bsdos-- #LIBS= -lresolv #CC=gcc2 #CF = cf/bsdos.h ##--bsdos-- ## FreeBSD ##--freebsd-- #CF = cf/freebsd.h #SCRIPT=freebsd ##--freebsd-- ## Rhapsody ##--rhapsody-- #CF = cf/rhapsody.h #COPTS = -Wall -Wno-unused -Wno-implicit -Wno-comment \ # -Wno-uninitialized -Werror -pipe #SCRIPT=rhapsody ##--rhapsody-- ## NetBSD ##--netbsd-- #CF = cf/netbsd.h #COPTS = -Wall -Wstrict-prototypes -Wno-unused -Wno-implicit -Wno-comment \ # -Wno-uninitialized -Werror -pipe #SCRIPT=netbsd ##--netbsd-- ## Ultrix ##--ultrix-- #BINDIR = /usr/etc #CLIENTBINDIR=/etc #VARRUN = /etc #VARDB = /etc #CF = cf/ultrix.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 ##--ultrix-- ## Linux 1.x ##--linux-1-- #COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) #CF = cf/linux.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 #MANCAT = man #VARRUN = /var/run #VARDB = /var/state/dhcp # see rationale in includes/cf/linux.h #SCRIPT=linux ##--linux-1-- ## Linux 2.0 ##--linux-2.0-- #COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) #CF = cf/linux.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 #MANCAT = man #VARRUN = /var/run #VARDB = /var/state/dhcp # see rationale in includes/cf/linux.h #SCRIPT=linux ##--linux-2.0-- ## Linux 2.1 ##--linux-2.1-- #COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) #CF = cf/linux.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/share/man/man5 #FFMANEXT = .5 #MANCAT = man #VARRUN = /var/run #VARDB = /var/state/dhcp # see rationale in includes/cf/linux.h #SCRIPT=linux ##--linux-2.1-- ## Linux 2.2 ##--linux-2.2-- #COPTS = -DLINUX_MAJOR=$(MAJORVERSION) -DLINUX_MINOR=$(MINORVERSION) #CF = cf/linux.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/share/man/man5 #FFMANEXT = .5 #MANCAT = man #VARRUN = /var/run #VARDB = /var/state/dhcp # see rationale in includes/cf/linux.h #SCRIPT=linux ##--linux-2.2-- ## SCO ##--sco-- #CF = cf/sco.h #PREDEFINES=-DSCO -DBROKEN_ANSI #BINDIR = /usr/etc #CLIENTBINDIR=/etc #ADMMANDIR = /usr/man/cat.ADMN #ADMMANEXT = .ADMN.Z #FFMANDIR = /usr/man/cat.SFF #FFMANEXT = .SFF.Z #INSTALL = cp #MANFROM = < #MANINSTALL = compress #MANTO = > #VARRUN = /etc #VARDB = /etc #CATMANPAGES= ##--sco-- ## QNX ##--qnx-- #CF = cf/qnx.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 #MANCAT = man #VARRUN = /etc #COPTS=-w3 -Dlint #LFLAGS=$(DEBUG) "-Wl,op symfile" -l socket #MANINSTALL = /bin/true #INSTALL = cp #BINDIR = /etc #CLIENTBINDIR = /etc ##--qnx-- ## CygWin32 ##--cygwin32-- #CF = cf/cygwin32.h #ADMMANDIR = /usr/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/man/man5 #FFMANEXT = .5 #VARRUN = /etc #MANINSTALL = /bin/true #INSTALL = cp #BINDIR = /etc #CLIENTBINDIR = /etc #CC=/usr/local/i386-unknown-cygwin32/bin/gcc #AR=/usr/local/i386-unknown-cygwin32/bin/ar #AS=/usr/local/i386-unknown-cygwin32/bin/as #LD=/usr/local/i386-unknown-cygwin32/bin/ld #NM=/usr/local/i386-unknown-cygwin32/bin/nm #RANLIB=/usr/local/i386-unknown-cygwin32/bin/ranlib #STRIP=/usr/local/i386-unknown-cygwin32/bin/strip ##--cygwin32-- ## IRIX 6.x ##--irix-- #LIBS = -lbind #LFLAGS=$(DEBUG) -L/usr/local/lib -Wl,-woff,84 -Wl,-woff,85 -Wl,-woff,134 #CC=gcc #COPTS = -I/usr/local/include #CF = cf/irix.h #BINDIR = /usr/local/etc #ADMMANDIR = /usr/local/man/man8 #ADMMANEXT = .8 #FFMANDIR = /usr/local/man/man5 #FFMANEXT = .5 #MANCAT = man #INSTALL = install #MANINSTALL = install #CHMOD = chmod #ETC = /etc #VARRUN = /etc #VARDB = /usr/local/etc/dhcp ##--irix-- diff --git a/contrib/isc-dhcp/README b/contrib/isc-dhcp/README index 03f308f91036..cf1fa6032bd6 100644 --- a/contrib/isc-dhcp/README +++ b/contrib/isc-dhcp/README @@ -1,535 +1,535 @@

Internet Software Consortium

Dynamic Host Configuration Protocol Distribution

-

Version 2 Patchlevel 2

+

Version 2 Patchlevel 3

June 30, 2000

README FILE

You should read this file carefully before trying to install or use the ISC DHCP Distribution.

    TABLE OF CONTENTS
    WHERE TO FIND DOCUMENTATION
    RELEASE STATUS
    BUILDING THE DHCP DISTRIBUTION
    INSTALLING THE DHCP DISTRIBUTION
    USING THE DHCP DISTRIBUTION
    LINUX
    SO_ATTACH_FILTER UNDECLARED
    PROTOCOL NOT CONFIGURED
    BROADCAST
    FIREWALL RULES
    IP BOOTP AGENT
    MULTIPLE INTERFACES
    SCO
    HP-UX
    ULTRIX
    FreeBSD
    NeXTSTEP
    SOLARIS
    SUPPORT
    HOW TO REPORT BUGS
    KNOWN BUGS

    Where to find documentation

    Documentation for this software includes this README file, the RELNOTES file, and the manual pages, which are in the server, common, client and relay subdirectories. Internet standards relating to the DHCP protocol are stored in the doc subdirectory. You will have the best luck reading the manual pages if you build this software and then install it, although you can read them directly out of the distribution if you need to.

    DHCP server documentation is in the dhcpd man page. Information about the DHCP server lease database is in the dhcpd.leases man page. Server configuration documentation is in the dhcpd.conf man page as well as the dhcp-options man page. A sample DHCP server configuration is in the file server/dhcpd.conf. The source for the dhcpd, dhcpd.leases and dhcpd.conf man pages is in the server/ sub- directory in the distribution. The source for the dhcp-options.5 man page is in the common/ subdirectory.

    DHCP Client documentation is in the dhclient man page. DHCP client configuration documentation is in the dhclient.conf man page and the dhcp-options man page. The DHCP client configuration script is documented in the dhclient-script man page. The format of the DHCP client lease database is documented in the dhclient.leases man page. The source for all these man pages is in the client/ subdirectory in the distribution. In addition, the dhcp-options man page should be referred to for information about DHCP options.

    DHCP relay agent documentation is in the dhcrelay man page, the source for which is distributed in the relay/ subdirectory.

    To read installed manual pages, use the man command. Type "man page" where page is the name of the manual page. This will only work if you have installed the ISC DHCP distribution using the ``make install'' command (described later).

    If you want to read manual pages that aren't installed, you can type ``nroff -man page |more'' where page is the filename of the unformatted manual page. The filename of an unformatted manual page is the name of the manual page, followed by '.', followed by some number - 5 for documentation about files, and 8 for documentation about programs. For example, to read the dhcp-options man page, you would type ``nroff -man common/dhcp-options.5 |more'', assuming your current working directory is the top level directory of the ISC DHCP Distribution.

    If you do not have the nroff command, you can type ``more catpage'' where catpage is the filename of the catted man page. Catted man pages names are the name of the manual page followed by ".cat" followed by 5 or 8, as with unformatted manual pages.

    Please note that until you install the manual pages, the pathnames of files to which they refer will not be correct for your operating system.

    Release status

    This is the final release of Version 2 of the Internet Software Consortium DHCP Distribution. In version 2.0, this distribution includes a DHCP server, a DHCP client, and a BOOTP/DHCP relay agent. This release is stable.

    In this release, the server and relay agent currently work well on NetBSD, Linux after kernel version 2.0.30, FreeBSD, BSD/OS, Ultrix, Digital Alpha OSF/1, Solaris and SunOS 4.1.4. On AIX, HPUX, IRIX and Linux 2.0.30, only a single broadcast network interface is supported. They also runs on QNX as long as only one broadcast network interface is configured and a host route is added from that interface to the 255.255.255.255 broadcast address.

    The DHCP client currently only knows how to configure the network on NetBSD, FreeBSD, BSD/os, Linux, Solaris and NextStep. The client depends on a system-dependent shell script to do network configuration - support for other operating systems is simply a matter of porting this shell script to the new platform.

    If you wish to run the DHCP Distribution on Linux, please see the Linux-specific notes later in this document. If you wish to run on an SCO release, please see the SCO-specific notes later in this document. You particularly need to read these notes if you intend to support Windows 95 clients. If you are running a version of FreeBSD prior to 2.2, please read the note on FreeBSD. If you are running HP-UX or Ultrix, please read the notes for those operating systems below. If you are running NeXTSTEP, please see the notes on NeXTSTEP below.

    If you start dhcpd and get a message, "no free bpf", that means you need to configure the Berkeley Packet Filter into your operating system kernel. On NetBSD, FreeBSD and BSD/os, type ``man bpf'' for information. On Digital Unix, type ``man pfilt''.

    Building the DHCP Distribution

    To build the DHCP Distribution, unpack the compressed tar file using the tar utility and the gzip command - type something like:

    - zcat dhcp-2.0pl2.tar.gz |tar xvf - + zcat dhcp-2.0pl3.tar.gz |tar xvf -

    On BSD/OS, you have to type gzcat, not zcat, and you may run into similar problems on other operating systems.

    -

    Now, cd to the dhcp-2.0pl2 subdirectory that you've just created and +

    Now, cd to the dhcp-2.0pl3 subdirectory that you've just created and configure the source tree by typing:

    ./configure

    If the configure utility can figure out what sort of system you're running on, it will create a custom Makefile for you for that system; otherwise, it will complain. If it can't figure out what system you are using, that system is not supported - you are on your own.

    Once you've run configure, just type ``make'', and after a while you should have a dhcp server. If you get compile errors on one of the supported systems mentioned earlier, please let us know. If you get warnings, it's not likely to be a problem - the DHCP server compiles completely warning-free on as many architectures as we can manage, but there are a few for which this is difficult. If you get errors on a system not mentioned above, you will need to do some programming or debugging on your own to get the DHCP Distribution working.

    Installing the dhcp distribution

    Once you have successfully gotten the DHCP Distribution to build, you can install it by typing ``make install''. If you already have an old version of the DHCP Distribution installed, you may want to save it before typing ``make install''.

    Using the dhcp distribution

    Linux

    There are three big LINUX issues: the all-ones broadcast address, Linux 2.1 ip_bootp_agent enabling, and operations with more than one network interface. There are also two potential compilation/runtime problems for Linux 2.1/2.2: the "SO_ATTACH_FILTER undeclared" problem and the "protocol not configured" problem.

    So_attach_filter undeclared

    In addition, there is a minor issue that we will mention here because this release is so close on the heels of the Linux 2.2 release: there is a symlink in /usr/include that points at the linux asm headers. It appears to be not uncommon that this link won't be updated correctly, in which case you'll get the following error when you try to build:

    lpf.c: In function `if_register_receive': lpf.c:152: `SO_ATTACH_FILTER' undeclared (first use this function) lpf.c:152: (Each undeclared identifier is reported only once lpf.c:152: for each function it appears in.)

    The line numbers may be different, of course. If you see this header, your linux asm header link is probably bad, and you should make sure it's pointing to correct linux source directory.

    Protocol not configured

    One additional Linux 2.1/2.2 issue: if you get the following message, it's because your kernel doesn't have the linux packetfilter or raw packet socket configured:

    Make sure CONFIG_PACKET (Packet socket) and CONFIG_FILTER (Socket Filtering) are enabled in your kernel configuration

    If this happens, you need to configure your Linux kernel to support Socket Filtering and the Packet socket. You can do this by typing ``make config'', ``make menuconfig'' or ``make xconfig'', and then enabling the Packet socket and Socket Filtering options that you'll see displayed on the menu or in the questionnaire. You can also edit your linux kernel .config file directly: set CONFIG_FILTER=y and CONFIG_PACKET=y. If you do this, make sure you run ``make oldconfig'' afterwards, so that the changes you've made are propogated to the kernel header files. After you've reconfigured, you need to type ``make'' to build a new Linux kernel, and then install it in the appropriate place (probably /linux). Make sure to save a copy of your old /linux.

    If the preceding paragraph made no sense to you, ask your Linux vendor/guru for help - please don't ask us.

    If you set CONFIG_PACKET=m or CONFIG_FILTER=m, then you must tell the kernel module loader to load the appropriate modules. If this doesn't make sense to you, don't use CONFIG_whatever=m - use CONFIG_whatever=y. Don't ask for help with this on the DHCP mailing list - it's a Linux kernel issue. This is probably not a problem with the most recent Linux 2.2.x kernels.

    Broadcast

    In order for dhcpd to work correctly with picky DHCP clients (e.g., Windows 95), it must be able to send packets with an IP destination address of 255.255.255.255. Unfortunately, Linux changes an IP destination of 255.255.255.255 into the local subnet broadcast address (here, that's 192.5.5.223). This isn't a problem on Linux 2.2 and later kernels, since we completely bypass the Linux IP stack, but on old versions of Linux 2.1 and all versions of Linux prior to 2.1, it is a problem - pickier DHCP clients connected to the same network as the ISC DHCP server or ISC relay agent will not see messages from the DHCP server.

    It is possible to work around this problem on some versions of Linux by creating a host route from your network interface address to 255.255.255.255. The command you need to use to do this on Linux varies from version to version. The easiest version is:

    route add -host 255.255.255.255 dev eth0

    On some older Linux systems, you will get an error if you try to do this. On those systems, try adding the following entry to your /etc/hosts file:

    255.255.255.255 all-ones

    Then, try:

    route add -host all-ones dev eth0

    Another route that has worked for some users is:

    route add -net 255.255.255.0 dev eth0

    If you are not using eth0 as your network interface, you should specify the network interface you *are* using in your route command.

    Firewall rules

    If you are running the DHCP server or client on a Linux system that's also acting as a firewall, you must be sure to allow DHCP packets through the firewall - Linux firewalls make filtering decisions before they make the forwarding decision, so they will filter packets that are intended for the firewall itself, as well as packets intended to be forwarded. In particular, your firewall rules _must_ allow packets from IP address 0.0.0.0 to IP address 255.255.255.255 from UDP port 68 to UDP port 67 through. They must also allow packets from your local firewall's IP address and UDP port 67 through to any address your DHCP server might serve on UDP port 68. Finally, packets from relay agents on port 67 to the DHCP server on port 67, and vice versa, must be permitted.

    IP BOOTP agent

    Some versions of the Linux 2.1 kernel apparently prevent dhcpd from working unless you enable it by doing the following:

    echo 1 >/proc/sys/net/ipv4/ip_bootp_agent

    Multiple interfaces

    Very old versions of the Linux kernel do not provide a networking API that allows dhcpd to operate correctly if the system has more than one broadcast network interface. However, Linux 2.0 kernels with version numbers greater than or equal to 2.0.31 add an API feature: the SO_BINDTODEVICE socket option. If SO_BINDTODEVICE is present, it is possible for dhcpd to operate on Linux with more than one network interface. In order to take advantage of this, you must be running a 2.0.31 or greater kernel, and you must have 2.0.31 or later system headers installed *before* you build the DHCP Distribution.

    We have heard reports that you must still add routes to 255.255.255.255 in order for the all-ones broadcast to work, even on 2.0.31 kernels. In fact, you now need to add a route for each interface. Hopefully the Linux kernel gurus will get this straight eventually.

    Linux 2.1 and later kernels do not use SO_BINDTODEVICE or require the broadcast address hack, but do support multiple interfaces, using the Linux Packet Filter.

    SCO

    SCO has the same problem as Linux (described earlier). The thing is, SCO *really* doesn't want to let you add a host route to the all-ones broadcast address. One technique that has been successful on some versions of SCO is the very bizarre command:

    ifconfig net0 alias 10.1.1.1 netmask 8.0.0.0

    Apparently this works because of an interaction between SCO's support for network classes and the weird netmask. The 10.* network is just a dummy that can generally be assumed to be safe. Don't ask why this works. Just try it. If it works for you, great. If not, SCO is supposedly adding hooks to support real DHCP service in a future release - I have this on good authority from the people at SCO who do *their* DHCP server and client.

    HP-UX

    HP-UX has the same problem with the all-ones broadcast address that SCO and Linux have. One user reported that adding the following to /etc/rc.config.d/netconf helped (you may have to modify this to suit your local configuration):

    INTERFACE_NAME[0]=lan0 IP_ADDRESS[0]=1.1.1.1 SUBNET_MASK[0]=255.255.255.0 BROADCAST_ADDRESS[0]="255.255.255.255" LANCONFIG_ARGS[0]="ether" DHCP_ENABLE[0]=0

    Ultrix

    Now that we have Ultrix packet filter support, the DHCP Distribution on Ultrix should be pretty trouble-free. However, one thing you do need to be aware of is that it now requires that the pfilt device be configured into your kernel and present in /dev. If you type ``man packetfilter'', you will get some information on how to configure your kernel for the packet filter (if it isn't already) and how to make an entry for it in /dev.

    FreeBSD

    Versions of FreeBSD prior to 2.2 have a bug in BPF support in that the ethernet driver swaps the ethertype field in the ethernet header downstream from BPF, which corrupts the output packet. If you are running a version of FreeBSD prior to 2.2, and you find that dhcpd can't communicate with its clients, you should #define BROKEN_FREEBSD_BPF in site.h and recompile.

    NeXTStep

    The NeXTSTEP support uses the NeXTSTEP Berkeley Packet Filter extension, which is not included in the base NextStep system. You must install this extension in order to get dhcpd or dhclient to work.

    Solaris

    One problem which has been observed and is not fixed in this patchlevel has to do with using DLPI on Solaris machines. The symptom of this problem is that the DHCP server never receives any requests. If you are using Solaris 2.6, and you encounter this symptom, and you are running the DHCP server on a machine with a single broadcast network interface, you may wish to edit the includes/site.h file and uncomment the #define USE_SOCKETS line. Then type ``make clean; make''.

    The DHCP client on Solaris will only work with DLPI. If you run it and it just keeps saying it's sending DHCPREQUEST packets, but never gets a response, you may be having DLPI trouble as described above. If so, you are SOL. Also, because Solaris requires you to "plumb" an interface before it can be detected by the DHCP client, you must either specify the name(s) of the interface(s) you want to configure on the command line, or must plumb the interfaces prior to invoking the DHCP client. This can be done with ``ifconfig iface plumb'', where iface is the name of the interface (e.g., ``ifconfig hme0 plumb'').

    It should be noted that Solaris versions from 2.6 onward include a DHCP client that you can run with ``/sbin/ifconfig iface dhcp start'' rather than using the ISC DHCP client. The feature set of the Solaris client is different (not necessarily better or worse) than that of the ISC client, but in most cases it will be a lot easier for you to just use that. Please do not ask for help in using the Solaris DHCP client on Internet Software Consortium mailing lists - that's why you're paying Sun the big bucks. If you're having a problem with the Solaris client interoperating with the ISC dhcp server, that's another matter, but please check with Sun first.

    Support

    The Internet Software Consortium DHCP server is not a commercial product, and is not supported in that sense. However, it has attracted a fairly sizable following on the Internet, which means that there are a lot of knowledgable users who may be able to help you if you get stuck. These people generally read the dhcp-server@fugue.com mailing list.

    If you are going to use dhcpd, you should probably subscribe to the dhcp-server and dhcp-announce mailing lists. If you will be using dhclient, you should subscribe to the dhcp-client mailing list.

    If you need help, you should ask on the dhcp-server or dhcp-client mailing list (or both) - whichever is appropriate to your application. This includes reporting bugs. Please do not report bugs in old software releases - fetch the latest release and see if the bug is still in that copy of the software, and if it's not, _then_ report it. It's okay to report bugs in the latest patchlevel of a major version that's not the most recent major version, though - for example, if you're running 2.0, you don't have to upgrade to 3.0 before you can report bugs.

    Please read this readme file carefully before reporting bugs!

    How to report bugs

    When you report bugs, please provide us complete information. A list of information we need follows. Please read it carefully, and put all the information you can into your initial bug report, so that we don't have to ask you any questions in order to figure out your problem.

    • The specific operating system name and version of the machine on which the DHCP server or client is running.
    • The specific operating system name and version of the machine on which the client is running, if you are having trouble getting a client working with the server.
    • If you're running Linux, the version number we care about is the kernel version and maybe the library version, not the distribution version - e.g., while we don't mind knowing that you're running Redhat version mumble.foo, we must know what kernel version you're running, and it helps if you can tell us what version of the C library you're running, although if you don't know that off the top of your head it may be hard for you to figure it out, so don't go crazy trying.
    • The specific version of the DHCP distribution you're running, for example 2.0b1pl19, not 2.0.
    • Please explain the problem carefully, thinking through what you're saying to ensure that you don't assume we know something about your situation that we don't know.
    • Include your dhcpd.conf and dhcpd.leases file if they're not huge (if they are huge, we may need them anyway, but don't send them until you're asked).
    • Include a log of your server or client running until it encounters the problem - for example, if you are having trouble getting some client to get an address, restart the server with the -d flag and then restart the client, and send us what the server prints. Likewise, with the client, include the output of the client as it fails to get an address or otherwise does the wrong thing. Do not leave out parts of the output that you think aren't interesting.
    • If the client or server is dumping core, please run the debugger and get a stack trace, and include that in your bug report. For example, if your debugger is gdb, do the following:
      gdb dhcpd dhcpd.core (gdb) where [...] (gdb) quit

      This assumes that it's the dhcp server you're debugging, and that the core file is in dhcpd.core.

    Please, do not send queries about non-isc clients to the dhcp-client mailing list. If you're asking about them on an ISC mailing list, it's probably because you're using the ISC DHCP server, so ask there. If you are having problems with a client whose executable is called dhcpcd, this is not the ISC DHCP client, and we probably can't help you with it.

    Please see http://www.fugue.com/dhcp/lists for details on how to subscribe. If you don't have WorldWide Web access, you can send mail to dhcp-request@fugue.com and tell me which lists you want to subscribe to, but please use the web interface if you can, since I have to handle the -request mailing list manually, and I will give you the third degree if you make me do your subscription manually.

    Please do not send requests for help directly to the author! The number of people using the DHCP Distribution is sufficiently large that if we take an interrupt every time any one of those people runs into trouble, we will never get any more coding done.

    Please do not call the author on the phone for support! Answering the phone takes a lot more time and attention than answering email. If you do call on the phone, you will be told to send email to the mailing list, so there's no point in doing it.

    Exception: if you are a support customer, you already know how to get in touch with us. To become a support customer, see our Support web page.

    Known bugs

    This release of the DHCP Distribution does not yet contain support for DHCPINFORM. The Vendor Specific Data option is not supported. Site- specific options are not supported. All of these are supported in the 3.0 release of the DHCP distribution, which is now in beta testing.

    diff --git a/contrib/isc-dhcp/RELNOTES b/contrib/isc-dhcp/RELNOTES index 7e7a5c3c81ee..60d2958de6ec 100644 --- a/contrib/isc-dhcp/RELNOTES +++ b/contrib/isc-dhcp/RELNOTES @@ -1,747 +1,754 @@ Internet Software Consortium Dynamic Host Configuration Protocol Distribution - Version 2 Patchlevel 2 - June 30, 2000 + Version 2 Patchlevel 3 + July 19, 2000 Release Notes Version 2 of the ISC DHCP Distribution includes the ISC DHCP server, DHCP Client and DHCP/BOOTP Relay Agent. This version has been in a near feature freeze since January of 1998, was in Beta test from that time to June of 1999, and has now been released in its final form. It has a number of important features, and is the release that we would expect most sites to run. For information on how to install, configure and run this software, as well as how to find documentation and report bugs, please consult the README file. CHANGELOG This log describes the changes that have been made in version 2.0 since June of 1997. + CHANGES FROM VERSION 2.0 PATCHLEVEL 2 + +- Rather than calling a client environment setup script, set the + environment up directly, so as to avoid any possible exploit making + use of clever shell metacharacter hacks. This is a security fix + that applies to the DHCP client *only*. + CHANGES FROM VERSION 2.0 PATCHLEVEL 1 - Fix a case where an unitialized pointer could result from an exceptional case in DHCPRELEASE and cause a core dump. CHANGES FROM VERSION 2.0 - Clean up DHCPRELEASE support. - Don't use the broadcast flag when doing BOOTP unless we need to. - Clean up the fallback mess. - Quote all shell special characters in the client script. - Fix ethernet header alignment on arm32. - Clarify the "no subnet declaration" message. - Correctly store the tftp server name in the lease file and the client script file. - Avoid a potential spin loop in client when script file creation fails for reasons other than the presence of an existing file of the same name. - Add support for Linux kernel versions greater than 2.2. - Fix a problem in raw.c on Irix. Thanks to Don Badrak for the patch. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 29 - Define BYTE_ORDER in includes/cf/hpux.h so that ip.h will compile correctly on HP-UX. - Fix a long-standing but minor bug in the way the program name for syslog was derived. - Fix a long-standing bug that prevented the DHCP server from broadcasting responses to BOOTP clients that requested a broadcast response. - In dhcprequest(), check to make sure that there's a lease before trying to acknowledge it to the client. This fixes a potential core dump that a few people observed. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 28 - Fix some pastos I introduced when merging Andrew Chittenden's token ring support. - Apply a patch to the token ring support from Andrew Chittenden. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 27 - Add dependencies to makefiles. - Don't use ping -w 1 in freebsd client script. - Token ring support for LPF, contributed by Andrew Chittenden. - Fix a subtle bug that would cause the server to respond incorrectly in some cases when the client sent duplicate DHCPREQUEST packets. - Fix option pretty printing for 'X' format. - Add some special cases to deal with DHCPREQUEST packets from RFC1541 clients. - Fix an obscure bug in nested subnet mask handling. - Fix a bug in abandoned lease reclamation. - Allow maximum message size to be set in configuration file. - Allow parameter request list to be supplied in configuration file. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 26 - Fix UDP/IP checksum code - Fix UDP payload length computation to prevent logging of spurious errors. - Support compilation on MacOS X - Add support for some options that were added in RFC2132. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 25 - Use the udp header's length rather than computing the length based on the number of bytes received, because some broken relay agents send packets with ip lengths that are longer than then sum of the ip header size and the udp length. - Do path keyword substitution on unformatted manual pages before installing them. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 24 - D'oh! Fix a really stupid mistake in hash.c. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 23 - Support an always-reply-rfc1048 flag, which says to reply with an RFC1048-style vendor extensions buffer even if the client didn't send an RFC1048-style magic number. - Fix a null pointer dereference. - Use netmask from subnet if no netmask option specified. - IRIX support (thanks to Don Badrak). - Install unformatted manual pages on Linux. - Add note in README about zcat vs. gzcat on BSD/os. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 22 - Test for lease before dereferencing it in dhcprequest. - Free the client parameter request list in dhcpnak if there is one. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 21 - Fix a pasto in options.c that will cause a core dump whenever a client sends in a request without a parameter request list. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 20 - Actually do the client fix mentioned below - Patchlevel 20 only contained half of the fix. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 19 - Removed arp table clearing code from solaris client script. - Document Linux "protocol not configured" error more thoroughly. - Clean up some unused variables. - Add entry and exit hooks to all dhcp client scripts, along with a make_resolv_conf function that can be redefined in the entry hooks. Document this new feature set. - Fix client to take advantage of network APIs that allow it to receive a unicast instead of requesting that the DHCP server broadcast its response. - Add -pf flag to all daemons allowing user to specify PID file name on command line. - Undo a previous change that attempted to be clever about testing interface flags but wound up being stupid instead. - Enforce access control on DHCPREQUEST messages as well as DHCPDISCOVER messages. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 18 - Support added for AIX 4.1.5.0 (and hopefully other versions). - Use /var/run instead of /etc on Digital Unix. - Change DHCP client exponential backoff code to back off more slowly, so that it is more robust in lossy environments, at the expense of being a bit less polite to the server. - Don't request a specific lease interval in the client unless the user says to do so. - Don't print DHCPXXX in wrong xxx messages unless DEBUG is defined. - Fix handling of secs field. - Fix handling of append statement. - Fix documentation for append and prepend statements. - Fix server support for parameter request list and maximum message size. - Parameterize more hardware types in discover_interfaces. Check for IFF_BROADCAST instead of !IFF_POINTOPOINT - Print kernel configuration warning message if we get EINVAL when opening or configuring the Linux packet filter. - Fix a bug in UDP checksum code (thanks to John Nemeth for figuring this out) and re-enable UDP checksumming. This allows the client to work with some buggy DHCP servers that can't handle zero checksums in the UDP header - in particular, the one John's cable modem ISP is using. - Don't report packet header checksum errors unless we see a lot of them. It's perfectly normal for some number of checksum errors to occur. - Refer to the dhcpd.leases man page when printing an error message prior to exiting because there's no lease database. - Add information to the README telling the reader how to get to the manual pages. - Fix the server packet transmission code to unicast when it can. - Fix a typo in the dhcpd.conf manual page. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 17 - Fix a bug in the relay agent where messages to the client would be unicast in the IP header but broadcast in the link header. The Microsoft DHCP client would reject such packets, preventing it from being configured. This was only a problem on non-socket-API platforms. - Do not attempt to reclaim requested abandoned leases in response to DHCPDISCOVER messages. - Allow the maximum lease time parameter in a host declaration to override the maximum lease time parameter in a subnet declaration. - Better document the -p flag for dhclient, dhcrelay and dhcpd. - Apply John Wehle's patch to fix the endianness bug in the dlpi packet filter on Solaris. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 16 - Fix linux man page install location. - Fix some confusion in the dhclient-script man page. - Fix error in includes/cf/linux.h that would have made network API selections in site.h work incorrectly. - Fix some major stupidity in the code that figures out where or not a client owns a particular lease. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 15 - Fix Makefile.conf on Linux to refer to /var/state/dhcp instead of /var/state/dhcpd. - Eliminate redundant #defines in includes/cf/linux.h (for neatness). - Fix an obscure case where dhcpd is started by the /etc/rc system with exactly the same pid each time, dhcpd.pid is not erased on reboot, and therefore dhcpd would detect a server (itself) with the pid in dhcpd.pid and decide that another server was running and exit. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 14 - Install the dhcp databases in /var/state/dhcp instead of /etc or /var/dhcpd, as suggested in the Linux Filesystem Hierarchy Standard. - Fix an endianness bug in dlpi.c. As a consequence, make the Solaris/i386 use dlpi again. - Fix a bunch of bugs in the Solaris client script. - Add some more information about Solaris to the README file. - Adjust startup message in interface probe so that the relay agent and client's unattached status will not trigger questions. - Update some error messages to provide more help to new users for some common mistakes. - Create an interface alias on Solaris when setting up IP aliases, rather than trying to do things the *BSD way. - Fix a null pointer dereference bug (this time I went through the whole function and audited it for more null pointer dereferences, and I didn't find any, for what that's worth). - Don't ever release leases in response to a DHCPDISCOVER (I think this was unlikely anyway, but why not be correct?). - Remove the shared-network example from the sample dhcpd.conf file. - Make ``make install'' make all first. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 13 - Support DESTDIR on installs. - Fix a bug in dhcp.c where a store through a null pointer would be made under some reasonably common circumstances. - Add test for ARPHRD_TUNNEL so that client and server do not fail on versions of Linux running IPsec implementations or the like. - Move tests for constants defined in O.S. headers into osdep.h - test for HAVE_whatever in .c files. Define relevant HAVE_whatevers in linux.h, so that versions of linux that define these constants as enums will still work. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 12 - Initialize the "quiet" variable in dhclient.c to zero (it was used without first having been initialized). - Fix the parser code for the authoritative keyword. - Adjust lease discovery code to NAK more aggressively for addresses the server knows it owns. - Add several new messages for DHCPNAK. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 11 - Use DLPI only on sparcs running Solaris, since it seems not to work on i386 boxes running Solaris for reasons yet to be determined. - In the client, close standard I/O descriptors when forking a daemon. - Don't let large lease lengths wrap lease expiry times - just use what fits into a TIME value. - Fix a bug in the SIOCGIFCONF interface scanning code. - Fix a core dump in the interface scanner that crops up on Linux when an interface is specified on the command line. - Don't use %D in strftime because egcs complains about it. - Print the error message if SO_BINDTODEVICE fails. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 10 - Update top-level Makefile so that it exits correctly on errors in submakes under bash/gnu make (dunno which is the culprit, and don't really care). - Print a more helpful message if no free BPF devices are found. - Add support for specifying that the server is or is not authoritative for a particular network segment. - Fix two stupid typos in lpf.c. - Print a more helpful message if we can't create an LPF socket or can't attach a filter to it. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 9 - Correct the hopelessly outdated information about Linux at the top of the README - many apologies to the Linux people who have had to read that nonsense for the past couple of snapshots and have been confused or annoyed by it. I simply hadn't read it recently, and didn't realize how out-of-date it was. - Print a message if the client finds no broadcast interfaces to configure. - Add support for use-lease-addr-for-default-route flag in server, so that Windows machines can be made to ARP for all addresses. - Update README file to mention new Linux gotchas. - After finally understanding Brian Murrel's code (my fault, not his) to get interface names from /proc/net/dev on Linux, fix what I broke of his code and document it. - Use sendto rather than send for SOCK_PACKET sockets, because they can't be connected, only bound. :'( - Fix up SOCK_PACKET creation so that the kernel doesn't complain about it. - Fix incorrect tests in linux client script: [ $relmajor == 2 ] -> [ $relmajor -eq 2 ] - Make typedefs for u8, u16 and u32 types. These are Linux kernel internal data types which are unfortunately exposed in the linux packetfilter header file. - Don't include in lpf.c - it defines things we're already correctly defining elsewhere, and doesn't define any useful new stuff. - Finally fix client PREINIT bug that causes interfaces not specified on the command line to be preinitialized. If no interfaces are specified on the command line, all interfaces are still preinitialized. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 8 - Fix socket API fallback setup code, which was causing Linux servers and clients to loop endlessly on select when run as daemons. - Add support for Linux 2.2 version number (treated the same as Linux 2.1, for now). - Correct apparent error in DHCPREQUEST destination address handling when in INIT-REBOOT state. - Do not set BROADCAST flag if we have a valid IP address. - Remove hard-coded filenames and use system-specific manifest constants. - Add entry and exit hooks to Linux dhclient-script (should be added to all operating systems once tested). - Test for linux major and minor version so as to correctly invoke network configuration programs. - Add support for Linux's gratuitous name change of bpf_insn structure (can't pollute precious Linux sources with the "Berkeley" word, I guess. - Correct USE_BPF_{SEND,RECEIVE} ifdefs for if_reinitialize_* functions. - Ensure that we have ifreq structure before initializing interface - if an interface was specified on the command line on Linux, this was not the case. - Get rid of references to enstamp structure in lpf.c. Correctly declare and initialize sock_fprog structure (aka bpf_filter structure on non-Linux machines). - Define ssize_t on Ultrix. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 7 - Generalize FDDI support. - Fix potential core dump in interface discovery code. - Put explicit release versions on startup messages. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 6 - Add support for Linux Packet Filter (thanks to Brian Murrell, Interlinx). - Add support for FDDI hardware type. - Fix a long-standing bug in DLPI support where the ethertype was being set incorrectly (thanks to Gong Wei, CCENet). - Don't use DLPI RAW mode on Solaris. - In the client, when a lease expires, the interface to which that lease is attached is unconfigured. On systems that use the socket API, the interface needs to then be reconfigured with the 0.0.0.0 address so that it can be used to get a new address. - Add fallback support for Linux. This fixes a problem with the relay agent when relaying over non-broadcast links, and may also fix some obscure problems with unicasting DHCPACKs in both the server and relay agent. - When allocating leases, if the oldest lease is abandoned, try to find a younger-but-still-expired lease rather than reclaiming the abandoned lease. - Add more documentation to README. - The absence of the /etc/dhclient.conf file is no longer considered an error. - The dhcp client's lease file name can be specified on the command line. - The DHCP client should no longer zap interfaces that it has not been directed to configure. - If a client starts up in the init-reboot state, the xid will be a "random" number rather than always being zero, as was previously the case. - In addition to comparing transaction IDs, compare hardware addresses in response packets to verify that they are ours. - Rewrite the client lease database after 20 leases have been written. - Fix the exponential backoff code. - Add a Y2k comment to indicate that something suspicious-looking is in fact _not_ a problem. - Use mkstemp if possible. - Add missing fi in various client scripts. - Use "search" instead of "domain" in linux resolv.conf files. - Specify a hop count in all route command on solaris. - If an allocation fails, don't try to zero out the allocation buffer we didn't get. - Support subnets that are subsets of other subnets - that is, for example, 10.0.1.0/24 and 10.0.0.0/16. This is useful in fairly obscure circumstances. - Don't set the lease end time if it's already expired. - Don't define INADDR_LOOPBACK on FreeBSD if it's already defined in a system header. - Use the broadcast address in the relay agent if we are using the BSD socket API. - Allow host declarations without names. - Allow the server identifier option to be specified. - Don't dump hostnames into the lease file if they contain non-printable characters. - Copy the entire client hardware address buffer that the client sends to the output packet, not just the portion of it that's supposedly significant according to the hardware address length field. This is done for the benefit of certain Microsoft clients. - Don't send a second ICMP echo request if we receive two DHCPDISCOVER messages in quick succession. This prevents a rather annoying timing race in configuring some Win95 clients. - Fix up dhcp-options man page to make it more readable. Note that netbios-name-server is the same thing as WINS. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 5 - Define some extra DLPI support flags that make DLPI work much better on Solaris. - Fix inet_aton prototype/declaration to match Internet Software Consortium BIND distribution. - Document new server-identifier functionality. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 4 - Do not use -Wstrict-prototypes on Solaris with gcc - if the Internet Software Consortium BIND distribution is not installed, this produces errors. - Actually use the new DLPI support on Solaris - although the code was added in Patchlevel 2, it wasn't enabled (blush). - Fix a prototype bug that's exposed when DLPI support is enabled on Solaris. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 3 - Fix a makefile botch that prevents the DHCP Distribution from from compiling on Solaris with gcc. Sigh. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 2 - Allow server-identifier in any scope. Use in-scope server identifier option rather than the default, if one exists. - Delete newlines from abandoned lease reclaimation warning. - Only release other applicable leases held by a client when the client sends a DHCPREQUEST. - Fix core dump when find_lease didn't find a lease. - Update dhcpd.leases man page. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 1 - Use -Wno-char-subscript on Solaris to prevent bogus warnings from gcc on Solaris 2.6. - Add support for Apple's new Rhapsody operating system. - Use DLPI on Solaris instead of using the BSD Sockets API. - Fix two network input buffer overflow problems which could allow an attacker to pervert the stack. - Fix an ancient typo that could theoretically cause memory corruption. - Sort abandoned leases in at current time rather than end of time. This allows abandoned leases to be reclaimed if there are no available free leases. - If a client explicitly requests a lease that's been abandoned, it's probably the system that was answering pings on that address, so let it have the lease. - Fix a bunch of type conversion errors that are flagged by the Solaris C compiler. CHANGES FROM VERSION 2.0 BETA 1 PATCHLEVEL 0 - Fix two potential buffer overflow problems. - Differentiate between versions of Linux for better success in compiling. - Fix bug in linux client script regarding routing setup. - Clarify socket API error message on multiple interfaces. - Fix broken comparison that was setting IP source address to zero. - Reclaim abandoned leases if we run out of free leases. CHANGES FROM THE DECEMBER 2, 1997 SNAPSHOT - Use %ld to print pid_t and cast pid_t values to long to avoid inconsistent declarations between different POSIX flavours. - Add support for ARPHRD_IEEE802 (token ring) hardware type. - If we own an address and a client requests it, but we can't assign it to that client, we now NAK it so that the client doesn't try to reuse it. CHANGES FROM THE JUNE SNAPSHOT - Support for NeXTstep 3.x and 4.x - Added man pages for dhcpd.leases, dhclient-script, dhclient.leases and dhclient.conf. Move general documentation of DHCP options into a seperate man page which is referred to by the dhclient.conf and dhcpd.conf man pages. - Updated README to answer some frequently asked questions. - Fixed a bug in command-line interface specification in dhclient - it was formerly not possible to specify that only certain interfaces be configured. - Do not leave client scripts lying around in /tmp after they've been used unless the -D flag is specified. - Add a new, non-standard, not-guaranteed-to-stay-the-same system configuration status message server which can be used to trigger the client to recheck its address, e.g., after a laptop has been put to sleep and then awakened (this has yet to be documented). - Fix handling of media selection in the REBOOT phase - previously the media type would not be remembered, which could cause severe delays in reacquiring an address if the default media type was wrong. - Allocate space for a NUL terminator on the end of client options - this was previously overlooked, and could cause garbage characters to be written to the temporary client script files. - Use mkstemp if it's available. - Supply network number and broadcast address to the client script so that on systems that need these values, they don't need to be computed with an awk script. - Keep a PID file for the client and the relay agent, and have the relay agent background itself by default. - Add client script for bsd/os, fix many niggling bugs in existing client scripts and add support for static routing tables to all bsd scripts. - Add a -q option to the client, server and relay agent so that they can be started from /etc/rc scripts without spewing a bunch of garbage on the console. By default, all three daemons still print startup messages, since these are helpful in bug reporting. - Don't print anything to stderr or stdout after going into background. - Fix bug where hostname keyword was not being recognized in dhcpd.leases file, resulting in the loss of lease database entries. - Fix problem on some operating systems where zero-length ifreq structures were being offset incorrectly when scanning the interface list on startup. - Unless a BOOTP client requests it, never send more than 64 bytes of options. - Don't ping static leases, since we don't have a lease structure on the heap to work with later. - Fixed a compile problem on Solaris 2.6. - Support interface aliases on Solaris. - Print day and month with leading zero in lease files if less than ten, for easier parsing by perl/sed/awk scripts. - Never make the lease database world writable, even if dhcpd is invoked with a bogus umask. - Fix DHCPRELEASE handling (before, addressed would never be released.) - If there is more than one lease for a particular client on a particular network, find the lease the client is asking for so as to avoid a cycle of NAKs. - If a BOOTP request is received from a particular client and that client has previously received a DHCP address, make sure that we still find a valid BOOTP lease so that we don't cycle through addresses. - Remove server-identifier option from documentation, other than to document that it has been deprecated. - Don't give up if we get an EINTR or EAGAIN while polling or selecting - these return statuses can occur spuriously without indicating a fatal problem. - Do not select for exceptions, since we don't handle them. This was causing massive CPU consumption on some systems. - When a DHCP client has been assigned a fixed address but had previously had a lease, it will request the old leased address. In such an event, send a DHCPNAK so that it will discover its new static binding. diff --git a/contrib/isc-dhcp/client/Makefile.dist b/contrib/isc-dhcp/client/Makefile.dist index 2109d3977c83..2b261a7e4610 100644 --- a/contrib/isc-dhcp/client/Makefile.dist +++ b/contrib/isc-dhcp/client/Makefile.dist @@ -1,136 +1,137 @@ # Makefile.dist # # Copyright (c) 1996, 1997, 1999 The Internet Software Consortium. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of The Internet Software Consortium nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND # CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL # THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # OF THE POSSIBILITY OF SUCH DAMAGE. # CATMANPAGES = dhclient.cat8 dhclient.conf.cat5 dhclient-script.cat8 \ dhclient.leases.cat5 SEDMANPAGES = dhclient.man8 dhclient.conf.man5 dhclient-script.man8 \ dhclient.leases.man5 SRCS = dhclient.c clparse.c OBJS = dhclient.o clparse.o PROG = dhclient MAN = dhclient.8 dhclient.conf.5 dhclient-script.8 dhclient.leases.5 DEBUG = -g INCLUDES = -I.. -I../includes DHCPLIB = ../common/libdhcp.a -CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) +CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) \ + -DCLIENT_PATH=${CLIENT_PATH} all: $(PROG) $(CATMANPAGES) install: all for dir in $(CLIENTBINDIR) $(ETC) $(FFMANDIR) $(ADMMANDIR) $(VARDB); \ do \ foo=""; \ for bar in `echo $(DESTDIR)$${dir} |tr / ' '`; do \ foo=$${foo}/$$bar; \ if [ ! -d $$foo ]; then \ mkdir $$foo; \ chmod 755 $$foo; \ fi; \ done; \ done $(INSTALL) dhclient $(DESTDIR)$(CLIENTBINDIR) $(CHMOD) 755 $(DESTDIR)$(CLIENTBINDIR)/dhclient if [ x$(SCRIPT) = xnone ]; then \ echo "No client script available."; \ else \ $(INSTALL) scripts/$(SCRIPT) $(DESTDIR)$(ETC)/dhclient-script; \ $(CHMOD) 700 $(DESTDIR)$(ETC)/dhclient-script; \ fi $(MANINSTALL) $(MANFROM) dhclient.$(MANCAT)8 $(MANTO) \ $(DESTDIR)$(ADMMANDIR)/dhclient$(ADMMANEXT) $(MANINSTALL) $(MANFROM) dhclient-script.$(MANCAT)8 $(MANTO) \ $(DESTDIR)$(ADMMANDIR)/dhclient-script$(ADMMANEXT) $(MANINSTALL) $(MANFROM) dhclient.conf.$(MANCAT)5 $(MANTO) \ $(DESTDIR)$(FFMANDIR)/dhclient.conf$(FFMANEXT) $(MANINSTALL) $(MANFROM) dhclient.leases.$(MANCAT)5 $(MANTO) \ $(DESTDIR)$(FFMANDIR)/dhclient.leases$(FFMANEXT) clean: -rm -f $(OBJS) realclean: clean -rm -f $(PROG) $(CATMANPAGES) $(SEDMANPAGES) *~ #* distclean: realclean -rm -f Makefile # These should only be done on 4.4 BSD-based systems, since the mandoc # macros aren't available on older unices. Catted man pages are # provided in the distribution so that this doesn't become a problem. dhclient.cat8: dhclient.man8 nroff -man dhclient.man8 >dhclient.cat8 dhclient.man8: dhclient.8 sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ -e "s#RUNDIR#$(VARRUN)#g" < dhclient.8 >dhclient.man8 dhclient-script.cat8: dhclient-script.man8 nroff -man dhclient-script.man8 >dhclient-script.cat8 dhclient-script.man8: dhclient-script.8 sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ -e "s#RUNDIR#$(VARRUN)#g" < dhclient-script.8 \ >dhclient-script.man8 dhclient.conf.man5: dhclient.conf.5 sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ -e "s#RUNDIR#$(VARRUN)#g" < dhclient.conf.5 \ >dhclient.conf.man5 dhclient.conf.cat5: dhclient.conf.man5 nroff -man dhclient.conf.man5 >dhclient.conf.cat5 dhclient.leases.man5: dhclient.leases.5 sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \ -e "s#RUNDIR#$(VARRUN)#g" < dhclient.leases.5 \ >dhclient.leases.man5 dhclient.leases.cat5: dhclient.leases.man5 nroff -man dhclient.leases.man5 >dhclient.leases.cat5 dhclient: $(OBJS) $(DHCPLIB) $(CC) $(LFLAGS) -o $(PROG) $(OBJS) $(DHCPLIB) $(LIBS) # Dependencies (semi-automatically-generated) dhclient.o: dhclient.c ../includes/dhcpd.h \ ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ ../includes/cf/netbsd.h ../includes/dhcp.h \ ../includes/tree.h ../includes/hash.h ../includes/inet.h \ ../includes/sysconf.h ../includes/version.h clparse.o: clparse.c ../includes/dhcpd.h \ ../includes/cdefs.h ../includes/osdep.h ../includes/site.h \ ../includes/cf/netbsd.h ../includes/dhcp.h \ ../includes/tree.h ../includes/hash.h ../includes/inet.h \ ../includes/sysconf.h ../includes/dhctoken.h diff --git a/contrib/isc-dhcp/client/clparse.c b/contrib/isc-dhcp/client/clparse.c index 6c12230b171d..b08e0b60c4ab 100644 --- a/contrib/isc-dhcp/client/clparse.c +++ b/contrib/isc-dhcp/client/clparse.c @@ -1,1009 +1,1012 @@ /* clparse.c Parser for dhclient config and lease files... */ /* * Copyright (c) 1997 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. */ #ifndef lint static char copyright[] = -"$Id: clparse.c,v 1.13.2.4 1999/03/29 21:21:37 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n"; +"$Id: clparse.c,v 1.13.2.5 2000/07/20 05:06:40 mellon Exp $ Copyright (c) 1997 The Internet Software Consortium. All rights reserved.\n" +"$FreeBSD$\n"; #endif /* not lint */ #include "dhcpd.h" #include "dhctoken.h" struct client_config top_level_config; +char client_script_name [] = "/sbin/dhclient-script"; + /* client-conf-file :== client-declarations EOF client-declarations :== | client-declaration | client-declarations client-declaration */ int read_client_conf () { FILE *cfile; char *val; int token; struct client_config *config; struct interface_info *ip; new_parse (path_dhclient_conf); /* Set up the initial dhcp option universe. */ initialize_universes (); /* Initialize the top level client configuration. */ memset (&top_level_config, 0, sizeof top_level_config); /* Set some defaults... */ top_level_config.timeout = 60; top_level_config.select_interval = 0; top_level_config.reboot_timeout = 10; top_level_config.retry_interval = 300; top_level_config.backoff_cutoff = 15; top_level_config.initial_interval = 3; top_level_config.bootp_policy = ACCEPT; - top_level_config.script_name = "/sbin/dhclient-script"; + top_level_config.script_name = client_script_name; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_SUBNET_MASK; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_BROADCAST_ADDRESS; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_TIME_OFFSET; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_ROUTERS; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME_SERVERS; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_HOST_NAME; if ((cfile = fopen (path_dhclient_conf, "r")) != NULL) { do { token = peek_token (&val, cfile); if (token == EOF) break; parse_client_statement (cfile, (struct interface_info *)0, &top_level_config); } while (1); token = next_token (&val, cfile); /* Clear the peek buffer */ fclose (cfile); } /* Set up state and config structures for clients that don't have per-interface configuration declarations. */ config = (struct client_config *)0; for (ip = interfaces; ip; ip = ip -> next) { if (!ip -> client) { ip -> client = (struct client_state *) malloc (sizeof (struct client_state)); if (!ip -> client) error ("no memory for client state."); memset (ip -> client, 0, sizeof *(ip -> client)); } if (!ip -> client -> config) { if (!config) { config = (struct client_config *) malloc (sizeof (struct client_config)); if (!config) error ("no memory for client config."); memcpy (config, &top_level_config, sizeof top_level_config); } ip -> client -> config = config; } } return !warnings_occurred; } /* lease-file :== client-lease-statements EOF client-lease-statements :== | client-lease-statements LEASE client-lease-statement */ void read_client_leases () { FILE *cfile; char *val; int token; new_parse (path_dhclient_db); /* Open the lease file. If we can't open it, just return - we can safely trust the server to remember our state. */ if ((cfile = fopen (path_dhclient_db, "r")) == NULL) return; do { token = next_token (&val, cfile); if (token == EOF) break; if (token != LEASE) { warn ("Corrupt lease file - possible data loss!"); skip_to_semi (cfile); break; } else parse_client_lease_statement (cfile, 0); } while (1); } /* client-declaration :== SEND option-decl | DEFAULT option-decl | SUPERSEDE option-decl | PREPEND option-decl | APPEND option-decl | hardware-declaration | REQUEST option-list | REQUIRE option-list | TIMEOUT number | RETRY number | REBOOT number | SELECT_TIMEOUT number | SCRIPT string | interface-declaration | LEASE client-lease-statement | ALIAS client-lease-statement */ void parse_client_statement (cfile, ip, config) FILE *cfile; struct interface_info *ip; struct client_config *config; { int token; char *val; struct option *option; switch (next_token (&val, cfile)) { case SEND: parse_option_decl (cfile, &config -> send_options [0]); return; case DEFAULT: option = parse_option_decl (cfile, &config -> defaults [0]); if (option) config -> default_actions [option -> code] = ACTION_DEFAULT; return; case SUPERSEDE: option = parse_option_decl (cfile, &config -> defaults [0]); if (option) config -> default_actions [option -> code] = ACTION_SUPERSEDE; return; case APPEND: option = parse_option_decl (cfile, &config -> defaults [0]); if (option) config -> default_actions [option -> code] = ACTION_APPEND; return; case PREPEND: option = parse_option_decl (cfile, &config -> defaults [0]); if (option) config -> default_actions [option -> code] = ACTION_PREPEND; return; case MEDIA: parse_string_list (cfile, &config -> media, 1); return; case HARDWARE: if (ip) { parse_hardware_param (cfile, &ip -> hw_address); } else { parse_warn ("hardware address parameter %s", "not allowed here."); skip_to_semi (cfile); } return; case REQUEST: config -> requested_option_count = parse_option_list (cfile, config -> requested_options); return; case REQUIRE: memset (config -> required_options, 0, sizeof config -> required_options); parse_option_list (cfile, config -> required_options); return; case TIMEOUT: parse_lease_time (cfile, &config -> timeout); return; case RETRY: parse_lease_time (cfile, &config -> retry_interval); return; case SELECT_TIMEOUT: parse_lease_time (cfile, &config -> select_interval); return; case REBOOT: parse_lease_time (cfile, &config -> reboot_timeout); return; case BACKOFF_CUTOFF: parse_lease_time (cfile, &config -> backoff_cutoff); return; case INITIAL_INTERVAL: parse_lease_time (cfile, &config -> initial_interval); return; case SCRIPT: config -> script_name = parse_string (cfile); return; case INTERFACE: if (ip) parse_warn ("nested interface declaration."); parse_interface_declaration (cfile, config); return; case LEASE: parse_client_lease_statement (cfile, 1); return; case ALIAS: parse_client_lease_statement (cfile, 2); return; case REJECT: parse_reject_statement (cfile, config); return; default: parse_warn ("expecting a statement."); skip_to_semi (cfile); break; } token = next_token (&val, cfile); if (token != SEMI) { parse_warn ("semicolon expected."); skip_to_semi (cfile); } } int parse_X (cfile, buf, max) FILE *cfile; u_int8_t *buf; int max; { int token; char *val; int len; token = peek_token (&val, cfile); if (token == NUMBER_OR_NAME || token == NUMBER) { len = 0; do { token = next_token (&val, cfile); if (token != NUMBER && token != NUMBER_OR_NAME) { parse_warn ("expecting hexadecimal constant."); skip_to_semi (cfile); return 0; } convert_num (&buf [len], val, 16, 8); if (len++ > max) { parse_warn ("hexadecimal constant too long."); skip_to_semi (cfile); return 0; } token = peek_token (&val, cfile); if (token == COLON) token = next_token (&val, cfile); } while (token == COLON); val = (char *)buf; } else if (token == STRING) { token = next_token (&val, cfile); len = strlen (val); if (len + 1 > max) { parse_warn ("string constant too long."); skip_to_semi (cfile); return 0; } memcpy (buf, val, len + 1); } else { parse_warn ("expecting string or hexadecimal data"); skip_to_semi (cfile); return 0; } return len; } /* option-list :== option_name | option_list COMMA option_name */ int parse_option_list (cfile, list) FILE *cfile; u_int8_t *list; { int ix, i; int token; char *val; ix = 0; do { token = next_token (&val, cfile); if (!is_identifier (token)) { parse_warn ("expected option name."); skip_to_semi (cfile); return 0; } for (i = 0; i < 256; i++) { if (!strcasecmp (dhcp_options [i].name, val)) break; } if (i == 256) { parse_warn ("%s: expected option name."); skip_to_semi (cfile); return 0; } list [ix++] = i; if (ix == 256) { parse_warn ("%s: too many options.", val); skip_to_semi (cfile); return 0; } token = next_token (&val, cfile); } while (token == COMMA); if (token != SEMI) { parse_warn ("expecting semicolon."); skip_to_semi (cfile); return 0; } return ix; } /* interface-declaration :== INTERFACE string LBRACE client-declarations RBRACE */ void parse_interface_declaration (cfile, outer_config) FILE *cfile; struct client_config *outer_config; { int token; char *val; struct interface_info *ip; token = next_token (&val, cfile); if (token != STRING) { parse_warn ("expecting interface name (in quotes)."); skip_to_semi (cfile); return; } ip = interface_or_dummy (val); if (!ip -> client) make_client_state (ip); if (!ip -> client -> config) make_client_config (ip, outer_config); ip -> flags &= ~INTERFACE_AUTOMATIC; interfaces_requested = 1; token = next_token (&val, cfile); if (token != LBRACE) { parse_warn ("expecting left brace."); skip_to_semi (cfile); return; } do { token = peek_token (&val, cfile); if (token == EOF) { parse_warn ("unterminated interface declaration."); return; } if (token == RBRACE) break; parse_client_statement (cfile, ip, ip -> client -> config); } while (1); token = next_token (&val, cfile); } struct interface_info *interface_or_dummy (name) char *name; { struct interface_info *ip; /* Find the interface (if any) that matches the name. */ for (ip = interfaces; ip; ip = ip -> next) { if (!strcmp (ip -> name, name)) break; } /* If it's not a real interface, see if it's on the dummy list. */ if (!ip) { for (ip = dummy_interfaces; ip; ip = ip -> next) { if (!strcmp (ip -> name, name)) break; } } /* If we didn't find an interface, make a dummy interface as a placeholder. */ if (!ip) { ip = ((struct interface_info *)malloc (sizeof *ip)); if (!ip) error ("Insufficient memory to record interface %s", name); memset (ip, 0, sizeof *ip); - strcpy (ip -> name, name); + strlcpy (ip -> name, name, IFNAMSIZ); ip -> next = dummy_interfaces; dummy_interfaces = ip; } return ip; } void make_client_state (ip) struct interface_info *ip; { ip -> client = ((struct client_state *)malloc (sizeof *(ip -> client))); if (!ip -> client) error ("no memory for state on %s\n", ip -> name); memset (ip -> client, 0, sizeof *(ip -> client)); } void make_client_config (ip, config) struct interface_info *ip; struct client_config *config; { ip -> client -> config = ((struct client_config *) malloc (sizeof (struct client_config))); if (!ip -> client -> config) error ("no memory for config for %s\n", ip -> name); memset (ip -> client -> config, 0, sizeof *(ip -> client -> config)); memcpy (ip -> client -> config, config, sizeof *config); } /* client-lease-statement :== RBRACE client-lease-declarations LBRACE client-lease-declarations :== | client-lease-declaration | client-lease-declarations client-lease-declaration */ void parse_client_lease_statement (cfile, is_static) FILE *cfile; int is_static; { struct client_lease *lease, *lp, *pl; struct interface_info *ip; int token; char *val; token = next_token (&val, cfile); if (token != LBRACE) { parse_warn ("expecting left brace."); skip_to_semi (cfile); return; } lease = (struct client_lease *)malloc (sizeof (struct client_lease)); if (!lease) error ("no memory for lease.\n"); memset (lease, 0, sizeof *lease); lease -> is_static = is_static; ip = (struct interface_info *)0; do { token = peek_token (&val, cfile); if (token == EOF) { parse_warn ("unterminated lease declaration."); return; } if (token == RBRACE) break; parse_client_lease_declaration (cfile, lease, &ip); } while (1); token = next_token (&val, cfile); /* If the lease declaration didn't include an interface declaration that we recognized, it's of no use to us. */ if (!ip) { free_client_lease (lease); return; } /* Make sure there's a client state structure... */ if (!ip -> client) make_client_state (ip); /* If this is an alias lease, it doesn't need to be sorted in. */ if (is_static == 2) { ip -> client -> alias = lease; return; } /* The new lease may supersede a lease that's not the active lease but is still on the lease list, so scan the lease list looking for a lease with the same address, and if we find it, toss it. */ pl = (struct client_lease *)0; for (lp = ip -> client -> leases; lp; lp = lp -> next) { if (lp -> address.len == lease -> address.len && !memcmp (lp -> address.iabuf, lease -> address.iabuf, lease -> address.len)) { if (pl) pl -> next = lp -> next; else ip -> client -> leases = lp -> next; free_client_lease (lp); break; } } /* If this is a preloaded lease, just put it on the list of recorded leases - don't make it the active lease. */ if (is_static) { lease -> next = ip -> client -> leases; ip -> client -> leases = lease; return; } /* The last lease in the lease file on a particular interface is the active lease for that interface. Of course, we don't know what the last lease in the file is until we've parsed the whole file, so at this point, we assume that the lease we just parsed is the active lease for its interface. If there's already an active lease for the interface, and this lease is for the same ip address, then we just toss the old active lease and replace it with this one. If this lease is for a different address, then if the old active lease has expired, we dump it; if not, we put it on the list of leases for this interface which are still valid but no longer active. */ if (ip -> client -> active) { if (ip -> client -> active -> expiry < cur_time) free_client_lease (ip -> client -> active); else if (ip -> client -> active -> address.len == lease -> address.len && !memcmp (ip -> client -> active -> address.iabuf, lease -> address.iabuf, lease -> address.len)) free_client_lease (ip -> client -> active); else { ip -> client -> active -> next = ip -> client -> leases; ip -> client -> leases = ip -> client -> active; } } ip -> client -> active = lease; /* phew. */ } /* client-lease-declaration :== BOOTP | INTERFACE string | FIXED_ADDR ip_address | FILENAME string | SERVER_NAME string | OPTION option-decl | RENEW time-decl | REBIND time-decl | EXPIRE time-decl */ void parse_client_lease_declaration (cfile, lease, ipp) FILE *cfile; struct client_lease *lease; struct interface_info **ipp; { int token; char *val; struct interface_info *ip; switch (next_token (&val, cfile)) { case BOOTP: lease -> is_bootp = 1; break; case INTERFACE: token = next_token (&val, cfile); if (token != STRING) { parse_warn ("expecting interface name (in quotes)."); skip_to_semi (cfile); break; } ip = interface_or_dummy (val); *ipp = ip; break; case FIXED_ADDR: if (!parse_ip_addr (cfile, &lease -> address)) return; break; case MEDIUM: parse_string_list (cfile, &lease -> medium, 0); return; case FILENAME: lease -> filename = parse_string (cfile); return; case SERVER_NAME: lease -> server_name = parse_string (cfile); return; case RENEW: lease -> renewal = parse_date (cfile); return; case REBIND: lease -> rebind = parse_date (cfile); return; case EXPIRE: lease -> expiry = parse_date (cfile); return; case OPTION: parse_option_decl (cfile, lease -> options); return; default: parse_warn ("expecting lease declaration."); skip_to_semi (cfile); break; } token = next_token (&val, cfile); if (token != SEMI) { parse_warn ("expecting semicolon."); skip_to_semi (cfile); } } struct option *parse_option_decl (cfile, options) FILE *cfile; struct option_data *options; { char *val; int token; u_int8_t buf [4]; u_int8_t hunkbuf [1024]; int hunkix = 0; char *vendor; char *fmt; struct universe *universe; struct option *option; struct iaddr ip_addr; u_int8_t *dp; int len; int nul_term = 0; token = next_token (&val, cfile); if (!is_identifier (token)) { parse_warn ("expecting identifier after option keyword."); if (token != SEMI) skip_to_semi (cfile); return (struct option *)0; } vendor = malloc (strlen (val) + 1); if (!vendor) error ("no memory for vendor information."); strcpy (vendor, val); token = peek_token (&val, cfile); if (token == DOT) { /* Go ahead and take the DOT token... */ token = next_token (&val, cfile); /* The next token should be an identifier... */ token = next_token (&val, cfile); if (!is_identifier (token)) { parse_warn ("expecting identifier after '.'"); if (token != SEMI) skip_to_semi (cfile); return (struct option *)0; } /* Look up the option name hash table for the specified vendor. */ universe = ((struct universe *) hash_lookup (&universe_hash, (unsigned char *)vendor, 0)); /* If it's not there, we can't parse the rest of the declaration. */ if (!universe) { parse_warn ("no vendor named %s.", vendor); skip_to_semi (cfile); return (struct option *)0; } } else { /* Use the default hash table, which contains all the standard dhcp option names. */ val = vendor; universe = &dhcp_universe; } /* Look up the actual option info... */ option = (struct option *)hash_lookup (universe -> hash, (unsigned char *)val, 0); /* If we didn't get an option structure, it's an undefined option. */ if (!option) { if (val == vendor) parse_warn ("no option named %s", val); else parse_warn ("no option named %s for vendor %s", val, vendor); skip_to_semi (cfile); return (struct option *)0; } /* Free the initial identifier token. */ free (vendor); /* Parse the option data... */ do { for (fmt = option -> format; *fmt; fmt++) { if (*fmt == 'A') break; switch (*fmt) { case 'X': len = parse_X (cfile, &hunkbuf [hunkix], sizeof hunkbuf - hunkix); hunkix += len; break; case 't': /* Text string... */ token = next_token (&val, cfile); if (token != STRING) { parse_warn ("expecting string."); skip_to_semi (cfile); return (struct option *)0; } len = strlen (val); if (hunkix + len + 1 > sizeof hunkbuf) { parse_warn ("option data buffer %s", "overflow"); skip_to_semi (cfile); return (struct option *)0; } memcpy (&hunkbuf [hunkix], val, len + 1); nul_term = 1; hunkix += len; break; case 'I': /* IP address. */ if (!parse_ip_addr (cfile, &ip_addr)) return (struct option *)0; len = ip_addr.len; dp = ip_addr.iabuf; alloc: if (hunkix + len > sizeof hunkbuf) { parse_warn ("option data buffer %s", "overflow"); skip_to_semi (cfile); return (struct option *)0; } memcpy (&hunkbuf [hunkix], dp, len); hunkix += len; break; case 'L': /* Unsigned 32-bit integer... */ case 'l': /* Signed 32-bit integer... */ token = next_token (&val, cfile); if (token != NUMBER) { need_number: parse_warn ("expecting number."); if (token != SEMI) skip_to_semi (cfile); return (struct option *)0; } convert_num (buf, val, 0, 32); len = 4; dp = buf; goto alloc; case 's': /* Signed 16-bit integer. */ case 'S': /* Unsigned 16-bit integer. */ token = next_token (&val, cfile); if (token != NUMBER) goto need_number; convert_num (buf, val, 0, 16); len = 2; dp = buf; goto alloc; case 'b': /* Signed 8-bit integer. */ case 'B': /* Unsigned 8-bit integer. */ token = next_token (&val, cfile); if (token != NUMBER) goto need_number; convert_num (buf, val, 0, 8); len = 1; dp = buf; goto alloc; case 'f': /* Boolean flag. */ token = next_token (&val, cfile); if (!is_identifier (token)) { parse_warn ("expecting identifier."); bad_flag: if (token != SEMI) skip_to_semi (cfile); return (struct option *)0; } if (!strcasecmp (val, "true") || !strcasecmp (val, "on")) buf [0] = 1; else if (!strcasecmp (val, "false") || !strcasecmp (val, "off")) buf [0] = 0; else { parse_warn ("expecting boolean."); goto bad_flag; } len = 1; dp = buf; goto alloc; default: warn ("Bad format %c in parse_option_param.", *fmt); skip_to_semi (cfile); return (struct option *)0; } } token = next_token (&val, cfile); } while (*fmt == 'A' && token == COMMA); if (token != SEMI) { parse_warn ("semicolon expected."); skip_to_semi (cfile); return (struct option *)0; } options [option -> code].data = (unsigned char *)malloc (hunkix + nul_term); if (!options [option -> code].data) error ("out of memory allocating option data."); memcpy (options [option -> code].data, hunkbuf, hunkix + nul_term); options [option -> code].len = hunkix; return option; } void parse_string_list (cfile, lp, multiple) FILE *cfile; struct string_list **lp; int multiple; { int token; char *val; struct string_list *cur, *tmp; /* Find the last medium in the media list. */ if (*lp) { for (cur = *lp; cur -> next; cur = cur -> next) ; } else { cur = (struct string_list *)0; } do { token = next_token (&val, cfile); if (token != STRING) { parse_warn ("Expecting media options."); skip_to_semi (cfile); return; } tmp = (struct string_list *)malloc (strlen (val) + 1 + sizeof (struct string_list *)); if (!tmp) error ("no memory for string list entry."); strcpy (tmp -> string, val); tmp -> next = (struct string_list *)0; /* Store this medium at the end of the media list. */ if (cur) cur -> next = tmp; else *lp = tmp; cur = tmp; token = next_token (&val, cfile); } while (multiple && token == COMMA); if (token != SEMI) { parse_warn ("expecting semicolon."); skip_to_semi (cfile); } } void parse_reject_statement (cfile, config) FILE *cfile; struct client_config *config; { int token; char *val; struct iaddr addr; struct iaddrlist *list; do { if (!parse_ip_addr (cfile, &addr)) { parse_warn ("expecting IP address."); skip_to_semi (cfile); return; } list = (struct iaddrlist *)malloc (sizeof (struct iaddrlist)); if (!list) error ("no memory for reject list!"); list -> addr = addr; list -> next = config -> reject_list; config -> reject_list = list; token = next_token (&val, cfile); } while (token == COMMA); if (token != SEMI) { parse_warn ("expecting semicolon."); skip_to_semi (cfile); } } diff --git a/contrib/isc-dhcp/client/dhclient.8 b/contrib/isc-dhcp/client/dhclient.8 index 096b1060c997..6cdc06350b29 100644 --- a/contrib/isc-dhcp/client/dhclient.8 +++ b/contrib/isc-dhcp/client/dhclient.8 @@ -1,212 +1,226 @@ .\" dhclient.8 .\" .\" Copyright (c) 1997 The Internet Software Consortium. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of The Internet Software Consortium nor the names .\" of its contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND .\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, .\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE .\" DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR .\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, .\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT .\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF .\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND .\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" This software has been written for the Internet Software Consortium .\" by Ted Lemon in cooperation with Vixie .\" Enterprises. To learn more about the Internet Software Consortium, .\" see ``http://www.isc.org/isc''. To learn more about Vixie .\" Enterprises, see ``http://www.vix.com''. +.\" +.\" Portions copyright (c) 2000 David E. O'Brien. +.\" All rights reserved. +.\" $FreeBSD$ +.\" .TH dhclient 8 .SH NAME dhclient - Dynamic Host Configuration Protocol Client .SH SYNOPSIS .B dhclient [ .B -Ddq1 ] [ +.B -cf +.I config-file +] +[ .B -lf .I lease-file ] [ .B -p .I port ] [ .B -pf .I pidfile ] [ .I if0 [ .I ...ifN ] ] .SH DESCRIPTION The Internet Software Consortium DHCP Client, dhclient, provides a means for configuring one or more network interfaces using the Dynamic Host Configuration Protocol, BOOTP protocol, or if these protocols fail, by statically assigning an address. .SH OPERATION .PP The DHCP protocol allows a host to contact a central server which maintains a list of IP addresses which may be assigned on one or more subnets. A DHCP client may request an address from this pool, and then use it on a temporary basis for communication on network. The DHCP protocol also provides a mechanism whereby a client can learn important details about the network to which it is attached, such as the location of a default router, the location of a name server, and so on. .PP On startup, dhclient reads the .IR dhclient.conf for configuration instructions. It then gets a list of all the network interfaces that are configured in the current system. For each interface, it attempts to configure the interface using the DHCP protocol. .PP In order to keep track of leases across system reboots and server restarts, dhclient keeps a list of leases it has been assigned in the dhclient.leases(5) file. On startup, after reading the dhclient.conf file, dhclient reads the dhclient.leases file to refresh its memory about what leases it has been assigned. .PP When a new lease is acquired, it is appended to the end of the dhclient.leases file. In order to prevent the file from becoming arbitrarily large, from time to time dhclient creates a new dhclient.leases file from its in-core lease database. The old version of the dhclient.leases file is retained under the name .IR dhcpd.leases~ until the next time dhclient rewrites the database. .PP Old leases are kept around in case the DHCP server is unavailable when dhclient is first invoked (generally during the initial system boot process). In that event, old leases from the dhclient.leases file which have not yet expired are tested, and if they are determined to be valid, they are used until either they expire or the DHCP server becomes available. .PP A mobile host which may sometimes need to access a network on which no DHCP server exists may be preloaded with a lease for a fixed address on that network. When all attempts to contact a DHCP server have failed, dhclient will try to validate the static lease, and if it succeeds, will use that lease until it is restarted. .PP A mobile host may also travel to some networks on which DHCP is not available but BOOTP is. In that case, it may be advantageous to arrange with the network administrator for an entry on the BOOTP database, so that the host can boot quickly on that network rather than cycling through the list of old leases. .SH COMMAND LINE .PP The names of the network interfaces that dhclient should attempt to configure may be specified on the command line. If no interface names are specified on the command line dhclient will identify all network interfaces, elimininating non-broadcast interfaces if possible, and attempt to configure each interface. .PP The .B -D flag causes .B dhclient to save the script it creates for use in conjunction with .B dhclient-script in .IR /tmp. .PP Dhclient will normally run in the foreground until it has configured an interface, and then will revert to running in the background. To run force dhclient to always run as a foreground process, the .B -d flag should be specified. This is useful when running dhclient under a debugger, or when running it out of inittab on System V systems. .PP If dhclient should listen and transmit on a port other than the standard (port 68), the .B -p flag may used. It should be followed by the udp port number that dhclient should use. This is mostly useful for debugging purposes. If the .B -p flag is specified, the client will transmit responses to servers at a port number that is one less than the one specified - i.e., if you specify .B -p 68, then the client will listen on port 68 and transmit to port 67. Datagrams that must go through relay agents are sent to the port number specified with the .B -p flag - if you wish to use alternate port numbers, you must configure any relay agents you are using to use the same alternate port numbers. .PP The +.B -cf +flag may be used to change the shell script from the default of +/sbin/dhclient-script. +.PP +The .B -lf flag may be used to change the lease output file from the default of /var/db/dhclient.leases. .PP The .B -pf flag may be used to change the PID file from the default of /var/run/dhclient.pid. .PP The .B -q flag may be used to reduce the amount of screen output from .B dhclient. .PP The .B -1 flag cause dhclient to try once to get a lease. If it fails, dhclient exits with exit code two. .PP .SH CONFIGURATION The syntax of the dhclient.conf(5) file is discussed separately. .SH FILES .B /etc/dhclient.conf, /var/db/dhclient.leases, /var/db/dhclient.leases~. .B /var/run/dhclient.pid, .SH SEE ALSO dhclient.conf(5), dhclient.leases(5), dhclient-script(8) .SH AUTHOR .B dhclient(8) has been written for the Internet Software Consortium by Ted Lemon in cooperation with Vixie Enterprises. To learn more about the Internet Software Consortium, see .B http://www.vix.com/isc. To learn more about Vixie Enterprises, see .B http://www.vix.com. .PP This client was substantially modified and enhanced by Elliot Poger for use on Linux while he was working on the MosquitoNet project at Stanford. .PP The current version owes much to Elliot's Linux enhancements, but was substantially reorganized and partially rewritten by Ted Lemon so as to use the same networking framework that the Internet Software Consortium DHCP server uses. Much system-specific configuration code was moved into a shell script so that as support for more operating systems is added, it will not be necessary to port and maintain system-specific configuration code to these operating systems - instead, the shell script can invoke the native tools to accomplish the same purpose. .PP diff --git a/contrib/isc-dhcp/client/dhclient.c b/contrib/isc-dhcp/client/dhclient.c index eeb241b58932..350ba0f39870 100644 --- a/contrib/isc-dhcp/client/dhclient.c +++ b/contrib/isc-dhcp/client/dhclient.c @@ -1,2183 +1,2248 @@ /* dhclient.c DHCP Client. */ /* * Copyright (c) 1995, 1996, 1997, 1998, 1999 * The Internet Software Consortium. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. * * This client was substantially modified and enhanced by Elliot Poger * for use on Linux while he was working on the MosquitoNet project at * Stanford. * * The current version owes much to Elliot's Linux enhancements, but * was substantially reorganized and partially rewritten by Ted Lemon * so as to use the same networking framework that the Internet Software * Consortium DHCP server uses. Much system-specific configuration code * was moved into a shell script so that as support for more operating * systems is added, it will not be necessary to port and maintain * system-specific configuration code to these operating systems - instead, * the shell script can invoke the native tools to accomplish the same * purpose. */ #ifndef lint static char ocopyright[] = -"$Id: dhclient.c,v 1.44.2.44 2000/01/26 12:51:11 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n" +"$Id: dhclient.c,v 1.44.2.45 2000/07/20 05:06:41 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n" "$FreeBSD$\n"; #endif /* not lint */ #include "dhcpd.h" #include "version.h" TIME cur_time; TIME default_lease_time = 43200; /* 12 hours... */ TIME max_lease_time = 86400; /* 24 hours... */ struct tree_cache *global_options [256]; char *path_dhclient_conf = _PATH_DHCLIENT_CONF; char *path_dhclient_db = _PATH_DHCLIENT_DB; char *path_dhclient_pid = _PATH_DHCLIENT_PID; int interfaces_requested = 0; int log_perror = 1; struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; struct iaddr iaddr_any = { 4, { 0, 0, 0, 0 } }; struct in_addr inaddr_any; struct sockaddr_in sockaddr_broadcast; /* ASSERT_STATE() does nothing now; it used to be assert (state_is == state_shouldbe). */ #define ASSERT_STATE(state_is, state_shouldbe) {} u_int16_t local_port; u_int16_t remote_port; int log_priority; int no_daemon; int save_scripts; int onetry; static char copyright[] = "Copyright 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium."; static char arr [] = "All rights reserved."; static char message [] = "Internet Software Consortium DHCP Client"; static char contrib [] = "Please contribute if you find this software useful."; static char url [] = "For info, please visit http://www.isc.org/dhcp-contrib.html"; static void usage PROTO ((char *)); int main (argc, argv, envp) int argc; char **argv, **envp; { int i; struct servent *ent; struct interface_info *ip; int seed; int quiet = 1; char *s; s = strrchr (argv [0], '/'); if (!s) s = argv [0]; else s++; /* Initially, log errors to stderr as well as to syslogd. */ #ifdef SYSLOG_4_2 openlog (s, LOG_NDELAY); log_priority = DHCPD_LOG_FACILITY; #else openlog (s, LOG_NDELAY, DHCPD_LOG_FACILITY); #endif #if !(defined (DEBUG) || defined (SYSLOG_4_2) || defined (__CYGWIN32__)) setlogmask (LOG_UPTO (LOG_INFO)); #endif for (i = 1; i < argc; i++) { if (!strcmp (argv [i], "-p")) { if (++i == argc) usage (s); local_port = htons (atoi (argv [i])); debug ("binding to user-specified port %d", ntohs (local_port)); } else if (!strcmp (argv [i], "-d")) { no_daemon = 1; } else if (!strcmp (argv [i], "-D")) { save_scripts = 1; + } else if (!strcmp (argv [i], "-cf")) { + if (++i == argc) + usage (s); + path_dhclient_conf = argv [i]; } else if (!strcmp (argv [i], "-pf")) { if (++i == argc) usage (s); path_dhclient_pid = argv [i]; } else if (!strcmp (argv [i], "-lf")) { if (++i == argc) usage (s); path_dhclient_db = argv [i]; } else if (!strcmp (argv [i], "-q")) { quiet = 1; quiet_interface_discovery = 1; } else if (!strcmp (argv [i], "-1")) { onetry = 1; } else if (argv [i][0] == '-') { usage (s); } else { struct interface_info *tmp = ((struct interface_info *) dmalloc (sizeof *tmp, "specified_interface")); if (!tmp) error ("Insufficient memory to %s %s", "record interface", argv [i]); memset (tmp, 0, sizeof *tmp); - strcpy (tmp -> name, argv [i]); + strlcpy (tmp -> name, argv [i], IFNAMSIZ); tmp -> next = interfaces; tmp -> flags = INTERFACE_REQUESTED; interfaces_requested = 1; interfaces = tmp; } } if (!quiet) { note ("%s %s", message, DHCP_VERSION); note (copyright); note (arr); note (""); note (contrib); note (url); note (""); } else log_perror = 0; /* Default to the DHCP/BOOTP port. */ if (!local_port) { ent = getservbyname ("dhcpc", "udp"); if (!ent) local_port = htons (68); else local_port = ent -> s_port; #ifndef __CYGWIN32__ endservent (); #endif } remote_port = htons (ntohs (local_port) - 1); /* XXX */ /* Get the current time... */ GET_TIME (&cur_time); sockaddr_broadcast.sin_family = AF_INET; sockaddr_broadcast.sin_port = remote_port; sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; #ifdef HAVE_SA_LEN sockaddr_broadcast.sin_len = sizeof sockaddr_broadcast; #endif inaddr_any.s_addr = INADDR_ANY; /* Discover all the network interfaces. */ discover_interfaces (DISCOVER_UNCONFIGURED); /* Parse the dhclient.conf file. */ read_client_conf (); /* Parse the lease database. */ read_client_leases (); /* Rewrite the lease database... */ rewrite_client_leases (); /* If no broadcast interfaces were discovered, call the script and tell it so. */ if (!interfaces) { script_init ((struct interface_info *)0, "NBI", (struct string_list *)0); script_go ((struct interface_info *)0); note ("No broadcast interfaces found - exiting."); /* Nothing more to do. */ exit (0); } else { /* Call the script with the list of interfaces. */ for (ip = interfaces; ip; ip = ip -> next) { /* If interfaces were specified, don't configure interfaces that weren't specified! */ if (interfaces_requested && ((ip -> flags & (INTERFACE_REQUESTED | INTERFACE_AUTOMATIC)) != INTERFACE_REQUESTED)) continue; script_init (ip, "PREINIT", (struct string_list *)0); if (ip -> client -> alias) script_write_params (ip, "alias_", ip -> client -> alias); script_go (ip); } } /* 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 up the interfaces. */ discover_interfaces (interfaces_requested ? DISCOVER_REQUESTED : DISCOVER_RUNNING); /* Make up a seed for the random number generator from current time plus the sum of the last four bytes of each interface's hardware address interpreted as an integer. Not much entropy, but we're booting, so we're not likely to find anything better. */ seed = 0; /* Unfortunately, what's on the stack isn't random. :') */ for (ip = interfaces; ip; ip = ip -> next) { int junk; memcpy (&junk, &ip -> hw_address.haddr [ip -> hw_address.hlen - sizeof seed], sizeof seed); seed += junk; } srandom (seed + cur_time); /* Start a configuration state machine for each interface. */ for (ip = interfaces; ip; ip = ip -> next) { ip -> client -> state = S_INIT; state_reboot (ip); } /* Set up the bootp packet handler... */ bootp_packet_handler = do_packet; /* Start dispatching packets and timeouts... */ dispatch (); /*NOTREACHED*/ return 0; } static void usage (appname) char *appname; { note (message); note (copyright); note (arr); note (""); note (contrib); note (url); note (""); - warn ("Usage: %s [-D] [-d] [-p ] [-lf lease-file]", appname); - error (" [-pf pidfile] [-q] [-1] [interface]"); + warn ("Usage: %s [-D] [-d] [-p ] [-cf conf-file]", appname); + error (" [-lf lease-file] [-pf pidfile] [-q] [-1] [interface]"); } void cleanup () { + /* Make sure the pidfile is gone. */ + unlink (path_dhclient_pid); } /* Individual States: * * Each routine is called from the dhclient_state_machine() in one of * these conditions: * -> entering INIT state * -> recvpacket_flag == 0: timeout in this state * -> otherwise: received a packet in this state * * Return conditions as handled by dhclient_state_machine(): * Returns 1, sendpacket_flag = 1: send packet, reset timer. * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). * Returns 0: finish the nap which was interrupted for no good reason. * * Several per-interface variables are used to keep track of the process: * active_lease: the lease that is being used on the interface * (null pointer if not configured yet). * offered_leases: leases corresponding to DHCPOFFER messages that have * been sent to us by DHCP servers. * acked_leases: leases corresponding to DHCPACK messages that have been * sent to us by DHCP servers. * sendpacket: DHCP packet we're trying to send. * destination: IP address to send sendpacket to * In addition, there are several relevant per-lease variables. * T1_expiry, T2_expiry, lease_expiry: lease milestones * In the active lease, these control the process of renewing the lease; * In leases on the acked_leases list, this simply determines when we * can no longer legitimately use the lease. */ void state_reboot (ipp) void *ipp; { struct interface_info *ip = ipp; /* If we don't remember an active lease, go straight to INIT. */ if (!ip -> client -> active || ip -> client -> active -> is_bootp) { state_init (ip); return; } /* We are in the rebooting state. */ ip -> client -> state = S_REBOOTING; /* make_request doesn't initialize xid because it normally comes from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, so pick an xid now. */ ip -> client -> xid = random (); /* Make a DHCPREQUEST packet, and set appropriate per-interface flags. */ make_request (ip, ip -> client -> active); ip -> client -> destination = iaddr_broadcast; ip -> client -> first_sending = cur_time; ip -> client -> interval = ip -> client -> config -> initial_interval; /* Zap the medium list... */ ip -> client -> medium = (struct string_list *)0; /* Send out the first DHCPREQUEST packet. */ send_request (ip); } /* Called when a lease has completely expired and we've been unable to renew it. */ void state_init (ipp) void *ipp; { struct interface_info *ip = ipp; ASSERT_STATE(state, S_INIT); /* Make a DHCPDISCOVER packet, and set appropriate per-interface flags. */ make_discover (ip, ip -> client -> active); ip -> client -> xid = ip -> client -> packet.xid; ip -> client -> destination = iaddr_broadcast; ip -> client -> state = S_SELECTING; ip -> client -> first_sending = cur_time; ip -> client -> interval = ip -> client -> config -> initial_interval; /* Add an immediate timeout to cause the first DHCPDISCOVER packet to go out. */ send_discover (ip); } /* state_selecting is called when one or more DHCPOFFER packets have been received and a configurable period of time has passed. */ void state_selecting (ipp) void *ipp; { struct interface_info *ip = ipp; struct client_lease *lp, *next, *picked; ASSERT_STATE(state, S_SELECTING); /* Cancel state_selecting and send_discover timeouts, since either one could have got us here. */ cancel_timeout (state_selecting, ip); cancel_timeout (send_discover, ip); /* We have received one or more DHCPOFFER packets. Currently, the only criterion by which we judge leases is whether or not we get a response when we arp for them. */ picked = (struct client_lease *)0; for (lp = ip -> client -> offered_leases; lp; lp = next) { next = lp -> next; /* Check to see if we got an ARPREPLY for the address in this particular lease. */ if (!picked) { script_init (ip, "ARPCHECK", lp -> medium); script_write_params (ip, "check_", lp); /* If the ARPCHECK code detects another machine using the offered address, it exits nonzero. We need to send a DHCPDECLINE and toss the lease. */ if (script_go (ip)) { make_decline (ip, lp); send_decline (ip); goto freeit; } picked = lp; picked -> next = (struct client_lease *)0; } else { freeit: free_client_lease (lp); } } ip -> client -> offered_leases = (struct client_lease *)0; /* If we just tossed all the leases we were offered, go back to square one. */ if (!picked) { ip -> client -> state = S_INIT; state_init (ip); return; } /* If it was a BOOTREPLY, we can just take the address right now. */ if (!picked -> options [DHO_DHCP_MESSAGE_TYPE].len) { ip -> client -> new = picked; /* Make up some lease expiry times XXX these should be configurable. */ ip -> client -> new -> expiry = cur_time + 12000; ip -> client -> new -> renewal += cur_time + 8000; ip -> client -> new -> rebind += cur_time + 10000; ip -> client -> state = S_REQUESTING; /* Bind to the address we received. */ bind_lease (ip); return; } /* Go to the REQUESTING state. */ ip -> client -> destination = iaddr_broadcast; ip -> client -> state = S_REQUESTING; ip -> client -> first_sending = cur_time; ip -> client -> interval = ip -> client -> config -> initial_interval; /* Make a DHCPREQUEST packet from the lease we picked. */ make_request (ip, picked); ip -> client -> xid = ip -> client -> packet.xid; /* Toss the lease we picked - we'll get it back in a DHCPACK. */ free_client_lease (picked); /* Add an immediate timeout to send the first DHCPREQUEST packet. */ send_request (ip); } /* state_requesting is called when we receive a DHCPACK message after having sent out one or more DHCPREQUEST packets. */ void dhcpack (packet) struct packet *packet; { struct interface_info *ip = packet -> interface; struct client_lease *lease; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (packet -> interface -> client -> xid != packet -> raw -> xid || (packet -> interface -> hw_address.hlen != packet -> raw -> hlen) || (memcmp (packet -> interface -> hw_address.haddr, packet -> raw -> chaddr, packet -> raw -> hlen))) { #if defined (DEBUG) debug ("DHCPACK in wrong transaction."); #endif return; } if (ip -> client -> state != S_REBOOTING && ip -> client -> state != S_REQUESTING && ip -> client -> state != S_RENEWING && ip -> client -> state != S_REBINDING) { #if defined (DEBUG) debug ("DHCPACK in wrong state."); #endif return; } note ("DHCPACK from %s", piaddr (packet -> client_addr)); lease = packet_to_lease (packet); if (!lease) { note ("packet_to_lease failed."); return; } ip -> client -> new = lease; /* Stop resending DHCPREQUEST. */ cancel_timeout (send_request, ip); /* Figure out the lease time. */ ip -> client -> new -> expiry = getULong (ip -> client -> new -> options [DHO_DHCP_LEASE_TIME].data); /* A number that looks negative here is really just very large, because the lease expiry offset is unsigned. */ if (ip -> client -> new -> expiry < 0) ip -> client -> new -> expiry = TIME_MAX; /* Take the server-provided renewal time if there is one; otherwise figure it out according to the spec. */ if (ip -> client -> new -> options [DHO_DHCP_RENEWAL_TIME].len) ip -> client -> new -> renewal = getULong (ip -> client -> new -> options [DHO_DHCP_RENEWAL_TIME].data); else ip -> client -> new -> renewal = ip -> client -> new -> expiry / 2; /* Same deal with the rebind time. */ if (ip -> client -> new -> options [DHO_DHCP_REBINDING_TIME].len) ip -> client -> new -> rebind = getULong (ip -> client -> new -> options [DHO_DHCP_REBINDING_TIME].data); else ip -> client -> new -> rebind = ip -> client -> new -> renewal + ip -> client -> new -> renewal / 2 + ip -> client -> new -> renewal / 4; ip -> client -> new -> expiry += cur_time; /* Lease lengths can never be negative. */ if (ip -> client -> new -> expiry < cur_time) ip -> client -> new -> expiry = TIME_MAX; ip -> client -> new -> renewal += cur_time; if (ip -> client -> new -> renewal < cur_time) ip -> client -> new -> renewal = TIME_MAX; ip -> client -> new -> rebind += cur_time; if (ip -> client -> new -> rebind < cur_time) ip -> client -> new -> rebind = TIME_MAX; bind_lease (ip); } void bind_lease (ip) struct interface_info *ip; { /* Remember the medium. */ ip -> client -> new -> medium = ip -> client -> medium; /* Write out the new lease. */ write_client_lease (ip, ip -> client -> new, 0); /* Run the client script with the new parameters. */ script_init (ip, (ip -> client -> state == S_REQUESTING ? "BOUND" : (ip -> client -> state == S_RENEWING ? "RENEW" : (ip -> client -> state == S_REBOOTING ? "REBOOT" : "REBIND"))), ip -> client -> new -> medium); if (ip -> client -> active && ip -> client -> state != S_REBOOTING) script_write_params (ip, "old_", ip -> client -> active); script_write_params (ip, "new_", ip -> client -> new); if (ip -> client -> alias) script_write_params (ip, "alias_", ip -> client -> alias); script_go (ip); /* Replace the old active lease with the new one. */ if (ip -> client -> active) free_client_lease (ip -> client -> active); ip -> client -> active = ip -> client -> new; ip -> client -> new = (struct client_lease *)0; /* Set up a timeout to start the renewal process. */ add_timeout (ip -> client -> active -> renewal, state_bound, ip); note ("bound to %s -- renewal in %d seconds.", piaddr (ip -> client -> active -> address), ip -> client -> active -> renewal - cur_time); ip -> client -> state = S_BOUND; reinitialize_interfaces (); go_daemon (); } /* state_bound is called when we've successfully bound to a particular lease, but the renewal time on that lease has expired. We are expected to unicast a DHCPREQUEST to the server that gave us our original lease. */ void state_bound (ipp) void *ipp; { struct interface_info *ip = ipp; ASSERT_STATE(state, S_BOUND); /* T1 has expired. */ make_request (ip, ip -> client -> active); ip -> client -> xid = ip -> client -> packet.xid; if (ip -> client -> active -> options [DHO_DHCP_SERVER_IDENTIFIER].len == 4) { memcpy (ip -> client -> destination.iabuf, ip -> client -> active -> options [DHO_DHCP_SERVER_IDENTIFIER].data, 4); ip -> client -> destination.len = 4; } else ip -> client -> destination = iaddr_broadcast; ip -> client -> first_sending = cur_time; ip -> client -> interval = ip -> client -> config -> initial_interval; ip -> client -> state = S_RENEWING; /* Send the first packet immediately. */ send_request (ip); } int commit_leases () { return 0; } int write_lease (lease) struct lease *lease; { return 0; } void db_startup () { } void bootp (packet) struct packet *packet; { struct iaddrlist *ap; if (packet -> raw -> op != BOOTREPLY) return; /* If there's a reject list, make sure this packet's sender isn't on it. */ for (ap = packet -> interface -> client -> config -> reject_list; ap; ap = ap -> next) { if (addr_eq (packet -> client_addr, ap -> addr)) { note ("BOOTREPLY from %s rejected.", piaddr (ap -> addr)); return; } } dhcpoffer (packet); } void dhcp (packet) struct packet *packet; { struct iaddrlist *ap; void (*handler) PROTO ((struct packet *)); char *type; switch (packet -> packet_type) { case DHCPOFFER: handler = dhcpoffer; type = "DHCPOFFER"; break; case DHCPNAK: handler = dhcpnak; type = "DHCPNACK"; break; case DHCPACK: handler = dhcpack; type = "DHCPACK"; break; default: return; } /* If there's a reject list, make sure this packet's sender isn't on it. */ for (ap = packet -> interface -> client -> config -> reject_list; ap; ap = ap -> next) { if (addr_eq (packet -> client_addr, ap -> addr)) { note ("%s from %s rejected.", type, piaddr (ap -> addr)); return; } } (*handler) (packet); } void dhcpoffer (packet) struct packet *packet; { struct interface_info *ip = packet -> interface; struct client_lease *lease, *lp; int i; int arp_timeout_needed, stop_selecting; char *name = (packet -> options [DHO_DHCP_MESSAGE_TYPE].len ? "DHCPOFFER" : "BOOTREPLY"); #ifdef DEBUG_PACKET dump_packet (packet); #endif /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (ip -> client -> state != S_SELECTING || packet -> interface -> client -> xid != packet -> raw -> xid || (packet -> interface -> hw_address.hlen != packet -> raw -> hlen) || (memcmp (packet -> interface -> hw_address.haddr, packet -> raw -> chaddr, packet -> raw -> hlen))) { #if defined (DEBUG) debug ("%s in wrong transaction.", name); #endif return; } note ("%s from %s", name, piaddr (packet -> client_addr)); /* If this lease doesn't supply the minimum required parameters, blow it off. */ for (i = 0; ip -> client -> config -> required_options [i]; i++) { if (!packet -> options [ip -> client -> config -> required_options [i]].len) { note ("%s isn't satisfactory.", name); return; } } /* If we've already seen this lease, don't record it again. */ for (lease = ip -> client -> offered_leases; lease; lease = lease -> next) { if (lease -> address.len == sizeof packet -> raw -> yiaddr && !memcmp (lease -> address.iabuf, &packet -> raw -> yiaddr, lease -> address.len)) { debug ("%s already seen.", name); return; } } lease = packet_to_lease (packet); if (!lease) { note ("packet_to_lease failed."); return; } /* If this lease was acquired through a BOOTREPLY, record that fact. */ if (!packet -> options [DHO_DHCP_MESSAGE_TYPE].len) lease -> is_bootp = 1; /* Record the medium under which this lease was offered. */ lease -> medium = ip -> client -> medium; /* Send out an ARP Request for the offered IP address. */ script_init (ip, "ARPSEND", lease -> medium); script_write_params (ip, "check_", lease); /* If the script can't send an ARP request without waiting, we'll be waiting when we do the ARPCHECK, so don't wait now. */ if (script_go (ip)) arp_timeout_needed = 0; else arp_timeout_needed = 2; /* Figure out when we're supposed to stop selecting. */ stop_selecting = (ip -> client -> first_sending + ip -> client -> config -> select_interval); /* If this is the lease we asked for, put it at the head of the list, and don't mess with the arp request timeout. */ if (lease -> address.len == ip -> client -> requested_address.len && !memcmp (lease -> address.iabuf, ip -> client -> requested_address.iabuf, ip -> client -> requested_address.len)) { lease -> next = ip -> client -> offered_leases; ip -> client -> offered_leases = lease; } else { /* If we already have an offer, and arping for this offer would take us past the selection timeout, then don't extend the timeout - just hope for the best. */ if (ip -> client -> offered_leases && (cur_time + arp_timeout_needed) > stop_selecting) arp_timeout_needed = 0; /* Put the lease at the end of the list. */ lease -> next = (struct client_lease *)0; if (!ip -> client -> offered_leases) ip -> client -> offered_leases = lease; else { for (lp = ip -> client -> offered_leases; lp -> next; lp = lp -> next) ; lp -> next = lease; } } /* If we're supposed to stop selecting before we've had time to wait for the ARPREPLY, add some delay to wait for the ARPREPLY. */ if (stop_selecting - cur_time < arp_timeout_needed) stop_selecting = cur_time + arp_timeout_needed; /* If the selecting interval has expired, go immediately to state_selecting(). Otherwise, time out into state_selecting at the select interval. */ if (stop_selecting <= 0) state_selecting (ip); else { add_timeout (stop_selecting, state_selecting, ip); cancel_timeout (send_discover, ip); } } /* Allocate a client_lease structure and initialize it from the parameters in the specified packet. */ struct client_lease *packet_to_lease (packet) struct packet *packet; { struct client_lease *lease; int i; lease = (struct client_lease *)malloc (sizeof (struct client_lease)); if (!lease) { warn ("dhcpoffer: no memory to record lease.\n"); return (struct client_lease *)0; } memset (lease, 0, sizeof *lease); /* Copy the lease options. */ for (i = 0; i < 256; i++) { if (packet -> options [i].len) { lease -> options [i].data = (unsigned char *) malloc (packet -> options [i].len + 1); if (!lease -> options [i].data) { warn ("dhcpoffer: no memory for option %d\n", i); free_client_lease (lease); return (struct client_lease *)0; } else { memcpy (lease -> options [i].data, packet -> options [i].data, packet -> options [i].len); lease -> options [i].len = packet -> options [i].len; lease -> options [i].data [lease -> options [i].len] = 0; } } } lease -> address.len = sizeof (packet -> raw -> yiaddr); memcpy (lease -> address.iabuf, &packet -> raw -> yiaddr, lease -> address.len); /* If the server name was filled out, copy it. */ if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len || !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 2)) && packet -> raw -> sname [0]) { int len; /* Don't count on the NUL terminator. */ for (len = 0; len < 64; len++) if (!packet -> raw -> sname [len]) break; lease -> server_name = malloc (len + 1); if (!lease -> server_name) { warn ("dhcpoffer: no memory for filename.\n"); free_client_lease (lease); return (struct client_lease *)0; } else { memcpy (lease -> server_name, packet -> raw -> sname, len); lease -> server_name [len] = 0; } } /* Ditto for the filename. */ if ((!packet -> options [DHO_DHCP_OPTION_OVERLOAD].len || !(packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 1)) && packet -> raw -> file [0]) { int len; /* Don't count on the NUL terminator. */ for (len = 0; len < 64; len++) if (!packet -> raw -> file [len]) break; lease -> filename = malloc (len + 1); if (!lease -> filename) { warn ("dhcpoffer: no memory for filename.\n"); free_client_lease (lease); return (struct client_lease *)0; } else { memcpy (lease -> filename, packet -> raw -> file, len); lease -> filename [len] = 0; } } return lease; } void dhcpnak (packet) struct packet *packet; { struct interface_info *ip = packet -> interface; /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (packet -> interface -> client -> xid != packet -> raw -> xid || (packet -> interface -> hw_address.hlen != packet -> raw -> hlen) || (memcmp (packet -> interface -> hw_address.haddr, packet -> raw -> chaddr, packet -> raw -> hlen))) { #if defined (DEBUG) debug ("DHCPNAK in wrong transaction."); #endif return; } if (ip -> client -> state != S_REBOOTING && ip -> client -> state != S_REQUESTING && ip -> client -> state != S_RENEWING && ip -> client -> state != S_REBINDING) { #if defined (DEBUG) debug ("DHCPNAK in wrong state."); #endif return; } note ("DHCPNAK from %s", piaddr (packet -> client_addr)); if (!ip -> client -> active) { note ("DHCPNAK with no active lease.\n"); return; } free_client_lease (ip -> client -> active); ip -> client -> active = (struct client_lease *)0; /* Stop sending DHCPREQUEST packets... */ cancel_timeout (send_request, ip); ip -> client -> state = S_INIT; state_init (ip); } /* Send out a DHCPDISCOVER packet, and set a timeout to send out another one after the right interval has expired. If we don't get an offer by the time we reach the panic interval, call the panic function. */ void send_discover (ipp) void *ipp; { struct interface_info *ip = ipp; int result; int interval; int increase = 1; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - ip -> client -> first_sending; /* If we're past the panic timeout, call the script and tell it we haven't found anything for this interface yet. */ if (interval > ip -> client -> config -> timeout) { state_panic (ip); return; } /* If we're selecting media, try the whole list before doing the exponential backoff, but if we've already received an offer, stop looping, because we obviously have it right. */ if (!ip -> client -> offered_leases && ip -> client -> config -> media) { int fail = 0; again: if (ip -> client -> medium) { ip -> client -> medium = ip -> client -> medium -> next; increase = 0; } if (!ip -> client -> medium) { if (fail) error ("No valid media types for %s!", ip -> name); ip -> client -> medium = ip -> client -> config -> media; increase = 1; } note ("Trying medium \"%s\" %d", ip -> client -> medium -> string, increase); script_init (ip, "MEDIUM", ip -> client -> medium); if (script_go (ip)) { goto again; } } /* If we're supposed to increase the interval, do so. If it's currently zero (i.e., we haven't sent any packets yet), set it to one; otherwise, add to it a random number between zero and two times itself. On average, this means that it will double with every transmission. */ if (increase) { if (!ip -> client -> interval) ip -> client -> interval = ip -> client -> config -> initial_interval; else { ip -> client -> interval += ((random () >> 2) % (2 * ip -> client -> interval)); } /* Don't backoff past cutoff. */ if (ip -> client -> interval > ip -> client -> config -> backoff_cutoff) ip -> client -> interval = ((ip -> client -> config -> backoff_cutoff / 2) + ((random () >> 2) % ip -> client -> config -> backoff_cutoff)); } else if (!ip -> client -> interval) ip -> client -> interval = ip -> client -> config -> initial_interval; /* If the backoff would take us to the panic timeout, just use that as the interval. */ if (cur_time + ip -> client -> interval > ip -> client -> first_sending + ip -> client -> config -> timeout) ip -> client -> interval = (ip -> client -> first_sending + ip -> client -> config -> timeout) - cur_time + 1; /* Record the number of seconds since we started sending. */ if (interval < 65536) ip -> client -> packet.secs = htons (interval); else ip -> client -> packet.secs = htons (65535); ip -> client -> secs = ip -> client -> packet.secs; note ("DHCPDISCOVER on %s to %s port %d interval %ld", ip -> name, inet_ntoa (sockaddr_broadcast.sin_addr), ntohs (sockaddr_broadcast.sin_port), ip -> client -> interval); /* Send out a packet. */ result = send_packet (ip, (struct packet *)0, &ip -> client -> packet, ip -> client -> packet_length, inaddr_any, &sockaddr_broadcast, (struct hardware *)0); add_timeout (cur_time + ip -> client -> interval, send_discover, ip); } /* state_panic gets called if we haven't received any offers in a preset amount of time. When this happens, we try to use existing leases that haven't yet expired, and failing that, we call the client script and hope it can do something. */ void state_panic (ipp) void *ipp; { struct interface_info *ip = ipp; struct client_lease *loop = ip -> client -> active; struct client_lease *lp; note ("No DHCPOFFERS received."); /* We may not have an active lease, but we may have some predefined leases that we can try. */ if (!ip -> client -> active && ip -> client -> leases) goto activate_next; /* Run through the list of leases and see if one can be used. */ while (ip -> client -> active) { if (ip -> client -> active -> expiry > cur_time) { note ("Trying recorded lease %s", piaddr (ip -> client -> active -> address)); /* Run the client script with the existing parameters. */ script_init (ip, "TIMEOUT", ip -> client -> active -> medium); script_write_params (ip, "new_", ip -> client -> active); if (ip -> client -> alias) script_write_params (ip, "alias_", ip -> client -> alias); /* If the old lease is still good and doesn't yet need renewal, go into BOUND state and timeout at the renewal time. */ if (!script_go (ip)) { if (cur_time < ip -> client -> active -> renewal) { ip -> client -> state = S_BOUND; note ("bound: renewal in %d seconds.", ip -> client -> active -> renewal - cur_time); add_timeout ((ip -> client -> active -> renewal), state_bound, ip); } else { ip -> client -> state = S_BOUND; note ("bound: immediate renewal."); state_bound (ip); } reinitialize_interfaces (); go_daemon (); return; } } /* If there are no other leases, give up. */ if (!ip -> client -> leases) { ip -> client -> leases = ip -> client -> active; ip -> client -> active = (struct client_lease *)0; break; } activate_next: /* Otherwise, put the active lease at the end of the lease list, and try another lease.. */ for (lp = ip -> client -> leases; lp -> next; lp = lp -> next) ; lp -> next = ip -> client -> active; if (lp -> next) { lp -> next -> next = (struct client_lease *)0; } ip -> client -> active = ip -> client -> leases; ip -> client -> leases = ip -> client -> leases -> next; /* If we already tried this lease, we've exhausted the set of leases, so we might as well give up for now. */ if (ip -> client -> active == loop) break; else if (!loop) loop = ip -> client -> active; } /* No leases were available, or what was available didn't work, so tell the shell script that we failed to allocate an address, and try again later. */ if (onetry) { exit(2); note ("Unable to obtain a lease on first try - exiting.\n"); } note ("No working leases in persistent database - sleeping.\n"); script_init (ip, "FAIL", (struct string_list *)0); if (ip -> client -> alias) script_write_params (ip, "alias_", ip -> client -> alias); script_go (ip); ip -> client -> state = S_INIT; add_timeout (cur_time + ip -> client -> config -> retry_interval, state_init, ip); go_daemon (); } void send_request (ipp) void *ipp; { struct interface_info *ip = ipp; int result; int interval; struct sockaddr_in destination; struct in_addr from; /* Figure out how long it's been since we started transmitting. */ interval = cur_time - ip -> client -> first_sending; /* If we're in the INIT-REBOOT or REQUESTING state and we're past the reboot timeout, go to INIT and see if we can DISCOVER an address... */ /* XXX In the INIT-REBOOT state, if we don't get an ACK, it means either that we're on a network with no DHCP server, or that our server is down. In the latter case, assuming that there is a backup DHCP server, DHCPDISCOVER will get us a new address, but we could also have successfully reused our old address. In the former case, we're hosed anyway. This is not a win-prone situation. */ if ((ip -> client -> state == S_REBOOTING || ip -> client -> state == S_REQUESTING) && interval > ip -> client -> config -> reboot_timeout) { cancel: ip -> client -> state = S_INIT; cancel_timeout (send_request, ip); state_init (ip); return; } /* If we're in the reboot state, make sure the media is set up correctly. */ if (ip -> client -> state == S_REBOOTING && !ip -> client -> medium && ip -> client -> active -> medium ) { script_init (ip, "MEDIUM", ip -> client -> active -> medium); /* If the medium we chose won't fly, go to INIT state. */ if (script_go (ip)) goto cancel; /* Record the medium. */ ip -> client -> medium = ip -> client -> active -> medium; } /* If the lease has expired, relinquish the address and go back to the INIT state. */ if (ip -> client -> state != S_REQUESTING && cur_time > ip -> client -> active -> expiry) { /* Run the client script with the new parameters. */ script_init (ip, "EXPIRE", (struct string_list *)0); script_write_params (ip, "old_", ip -> client -> active); if (ip -> client -> alias) script_write_params (ip, "alias_", ip -> client -> alias); script_go (ip); /* Now do a preinit on the interface so that we can discover a new address. */ script_init (ip, "PREINIT", (struct string_list *)0); if (ip -> client -> alias) script_write_params (ip, "alias_", ip -> client -> alias); script_go (ip); ip -> client -> state = S_INIT; state_init (ip); return; } /* Do the exponential backoff... */ if (!ip -> client -> interval) ip -> client -> interval = ip -> client -> config -> initial_interval; else { ip -> client -> interval += ((random () >> 2) % (2 * ip -> client -> interval)); } /* Don't backoff past cutoff. */ if (ip -> client -> interval > ip -> client -> config -> backoff_cutoff) ip -> client -> interval = ((ip -> client -> config -> backoff_cutoff / 2) + ((random () >> 2) % ip -> client -> interval)); /* If the backoff would take us to the expiry time, just set the timeout to the expiry time. */ if (ip -> client -> state != S_REQUESTING && cur_time + ip -> client -> interval > ip -> client -> active -> expiry) ip -> client -> interval = ip -> client -> active -> expiry - cur_time + 1; /* If the lease T2 time has elapsed, or if we're not yet bound, broadcast the DHCPREQUEST rather than unicasting. */ if (ip -> client -> state == S_REQUESTING || ip -> client -> state == S_REBOOTING || cur_time > ip -> client -> active -> rebind) destination.sin_addr.s_addr = INADDR_BROADCAST; else memcpy (&destination.sin_addr.s_addr, ip -> client -> destination.iabuf, sizeof destination.sin_addr.s_addr); destination.sin_port = remote_port; destination.sin_family = AF_INET; #ifdef HAVE_SA_LEN destination.sin_len = sizeof destination; #endif if (ip -> client -> state != S_REQUESTING) memcpy (&from, ip -> client -> active -> address.iabuf, sizeof from); else from.s_addr = INADDR_ANY; /* Record the number of seconds since we started sending. */ if (ip -> client -> state == S_REQUESTING) ip -> client -> packet.secs = ip -> client -> secs; else { if (interval < 65536) ip -> client -> packet.secs = htons (interval); else ip -> client -> packet.secs = htons (65535); } note ("DHCPREQUEST on %s to %s port %d", ip -> name, inet_ntoa (destination.sin_addr), ntohs (destination.sin_port)); if (destination.sin_addr.s_addr != INADDR_BROADCAST && fallback_interface) result = send_packet (fallback_interface, (struct packet *)0, &ip -> client -> packet, ip -> client -> packet_length, from, &destination, (struct hardware *)0); else /* Send out a packet. */ result = send_packet (ip, (struct packet *)0, &ip -> client -> packet, ip -> client -> packet_length, from, &destination, (struct hardware *)0); add_timeout (cur_time + ip -> client -> interval, send_request, ip); } void send_decline (ipp) void *ipp; { struct interface_info *ip = ipp; int result; note ("DHCPDECLINE on %s to %s port %d", ip -> name, inet_ntoa (sockaddr_broadcast.sin_addr), ntohs (sockaddr_broadcast.sin_port)); /* Send out a packet. */ result = send_packet (ip, (struct packet *)0, &ip -> client -> packet, ip -> client -> packet_length, inaddr_any, &sockaddr_broadcast, (struct hardware *)0); } void send_release (ipp) void *ipp; { struct interface_info *ip = ipp; int result; note ("DHCPRELEASE on %s to %s port %d", ip -> name, inet_ntoa (sockaddr_broadcast.sin_addr), ntohs (sockaddr_broadcast.sin_port)); /* Send out a packet. */ result = send_packet (ip, (struct packet *)0, &ip -> client -> packet, ip -> client -> packet_length, inaddr_any, &sockaddr_broadcast, (struct hardware *)0); } void make_discover (ip, lease) struct interface_info *ip; struct client_lease *lease; { unsigned char discover = DHCPDISCOVER; int i; struct tree_cache *options [256]; struct tree_cache option_elements [256]; memset (option_elements, 0, sizeof option_elements); memset (options, 0, sizeof options); memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ i = DHO_DHCP_MESSAGE_TYPE; options [i] = &option_elements [i]; options [i] -> value = &discover; options [i] -> len = sizeof discover; options [i] -> buf_size = sizeof discover; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; /* Request the options we want */ i = DHO_DHCP_PARAMETER_REQUEST_LIST; options [i] = &option_elements [i]; options [i] -> value = ip -> client -> config -> requested_options; options [i] -> len = ip -> client -> config -> requested_option_count; options [i] -> buf_size = ip -> client -> config -> requested_option_count; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; /* If we had an address, try to get it again. */ if (lease) { ip -> client -> requested_address = lease -> address; i = DHO_DHCP_REQUESTED_ADDRESS; options [i] = &option_elements [i]; options [i] -> value = lease -> address.iabuf; options [i] -> len = lease -> address.len; options [i] -> buf_size = lease -> address.len; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; } else { ip -> client -> requested_address.len = 0; } /* Send any options requested in the config file. */ for (i = 0; i < 256; i++) { if (!options [i] && ip -> client -> config -> send_options [i].data) { options [i] = &option_elements [i]; options [i] -> value = ip -> client -> config -> send_options [i].data; options [i] -> len = ip -> client -> config -> send_options [i].len; options [i] -> buf_size = ip -> client -> config -> send_options [i].len; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; } } /* Set up the option buffer... */ ip -> client -> packet_length = cons_options ((struct packet *)0, &ip -> client -> packet, 0, options, 0, 0, 0, (u_int8_t *)0, 0); if (ip -> client -> packet_length < BOOTP_MIN_LEN) ip -> client -> packet_length = BOOTP_MIN_LEN; ip -> client -> packet.op = BOOTREQUEST; ip -> client -> packet.htype = ip -> hw_address.htype; ip -> client -> packet.hlen = ip -> hw_address.hlen; ip -> client -> packet.hops = 0; ip -> client -> packet.xid = random (); ip -> client -> packet.secs = 0; /* filled in by send_discover. */ if (can_receive_unicast_unconfigured (ip)) ip -> client -> packet.flags = 0; else ip -> client -> packet.flags = htons (BOOTP_BROADCAST); memset (&(ip -> client -> packet.ciaddr), 0, sizeof ip -> client -> packet.ciaddr); memset (&(ip -> client -> packet.yiaddr), 0, sizeof ip -> client -> packet.yiaddr); memset (&(ip -> client -> packet.siaddr), 0, sizeof ip -> client -> packet.siaddr); memset (&(ip -> client -> packet.giaddr), 0, sizeof ip -> client -> packet.giaddr); memcpy (ip -> client -> packet.chaddr, ip -> hw_address.haddr, ip -> hw_address.hlen); #ifdef DEBUG_PACKET dump_packet (sendpkt); dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length); #endif } void make_request (ip, lease) struct interface_info *ip; struct client_lease *lease; { unsigned char request = DHCPREQUEST; int i; struct tree_cache *options [256]; struct tree_cache option_elements [256]; memset (options, 0, sizeof options); memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ i = DHO_DHCP_MESSAGE_TYPE; options [i] = &option_elements [i]; options [i] -> value = &request; options [i] -> len = sizeof request; options [i] -> buf_size = sizeof request; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; /* Request the options we want */ i = DHO_DHCP_PARAMETER_REQUEST_LIST; options [i] = &option_elements [i]; options [i] -> value = ip -> client -> config -> requested_options; options [i] -> len = ip -> client -> config -> requested_option_count; options [i] -> buf_size = ip -> client -> config -> requested_option_count; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; /* If we are requesting an address that hasn't yet been assigned to us, use the DHCP Requested Address option. */ if (ip -> client -> state == S_REQUESTING) { /* Send back the server identifier... */ i = DHO_DHCP_SERVER_IDENTIFIER; options [i] = &option_elements [i]; options [i] -> value = lease -> options [i].data; options [i] -> len = lease -> options [i].len; options [i] -> buf_size = lease -> options [i].len; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; } if (ip -> client -> state == S_REQUESTING || ip -> client -> state == S_REBOOTING) { ip -> client -> requested_address = lease -> address; i = DHO_DHCP_REQUESTED_ADDRESS; options [i] = &option_elements [i]; options [i] -> value = lease -> address.iabuf; options [i] -> len = lease -> address.len; options [i] -> buf_size = lease -> address.len; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; } else { ip -> client -> requested_address.len = 0; } /* Send any options requested in the config file. */ for (i = 0; i < 256; i++) { if (!options [i] && ip -> client -> config -> send_options [i].data) { options [i] = &option_elements [i]; options [i] -> value = ip -> client -> config -> send_options [i].data; options [i] -> len = ip -> client -> config -> send_options [i].len; options [i] -> buf_size = ip -> client -> config -> send_options [i].len; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; } } /* Set up the option buffer... */ ip -> client -> packet_length = cons_options ((struct packet *)0, &ip -> client -> packet, 0, options, 0, 0, 0, (u_int8_t *)0, 0); if (ip -> client -> packet_length < BOOTP_MIN_LEN) ip -> client -> packet_length = BOOTP_MIN_LEN; ip -> client -> packet.op = BOOTREQUEST; ip -> client -> packet.htype = ip -> hw_address.htype; ip -> client -> packet.hlen = ip -> hw_address.hlen; ip -> client -> packet.hops = 0; ip -> client -> packet.xid = ip -> client -> xid; ip -> client -> packet.secs = 0; /* Filled in by send_request. */ /* If we own the address we're requesting, put it in ciaddr; otherwise set ciaddr to zero. */ if (ip -> client -> state == S_BOUND || ip -> client -> state == S_RENEWING || ip -> client -> state == S_REBINDING) { memcpy (&ip -> client -> packet.ciaddr, lease -> address.iabuf, lease -> address.len); ip -> client -> packet.flags = 0; } else { memset (&ip -> client -> packet.ciaddr, 0, sizeof ip -> client -> packet.ciaddr); if (can_receive_unicast_unconfigured (ip)) ip -> client -> packet.flags = 0; else ip -> client -> packet.flags = htons (BOOTP_BROADCAST); } memset (&ip -> client -> packet.yiaddr, 0, sizeof ip -> client -> packet.yiaddr); memset (&ip -> client -> packet.siaddr, 0, sizeof ip -> client -> packet.siaddr); memset (&ip -> client -> packet.giaddr, 0, sizeof ip -> client -> packet.giaddr); memcpy (ip -> client -> packet.chaddr, ip -> hw_address.haddr, ip -> hw_address.hlen); #ifdef DEBUG_PACKET dump_packet (sendpkt); dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length); #endif } void make_decline (ip, lease) struct interface_info *ip; struct client_lease *lease; { unsigned char decline = DHCPDECLINE; int i; struct tree_cache *options [256]; struct tree_cache message_type_tree; struct tree_cache requested_address_tree; struct tree_cache server_id_tree; struct tree_cache client_id_tree; memset (options, 0, sizeof options); memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ i = DHO_DHCP_MESSAGE_TYPE; options [i] = &message_type_tree; options [i] -> value = &decline; options [i] -> len = sizeof decline; options [i] -> buf_size = sizeof decline; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; /* Send back the server identifier... */ i = DHO_DHCP_SERVER_IDENTIFIER; options [i] = &server_id_tree; options [i] -> value = lease -> options [i].data; options [i] -> len = lease -> options [i].len; options [i] -> buf_size = lease -> options [i].len; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; /* Send back the address we're declining. */ i = DHO_DHCP_REQUESTED_ADDRESS; options [i] = &requested_address_tree; options [i] -> value = lease -> address.iabuf; options [i] -> len = lease -> address.len; options [i] -> buf_size = lease -> address.len; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; /* Send the uid if the user supplied one. */ i = DHO_DHCP_CLIENT_IDENTIFIER; if (ip -> client -> config -> send_options [i].len) { options [i] = &client_id_tree; options [i] -> value = ip -> client -> config -> send_options [i].data; options [i] -> len = ip -> client -> config -> send_options [i].len; options [i] -> buf_size = ip -> client -> config -> send_options [i].len; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; } /* Set up the option buffer... */ ip -> client -> packet_length = cons_options ((struct packet *)0, &ip -> client -> packet, 0, options, 0, 0, 0, (u_int8_t *)0, 0); if (ip -> client -> packet_length < BOOTP_MIN_LEN) ip -> client -> packet_length = BOOTP_MIN_LEN; ip -> client -> packet.op = BOOTREQUEST; ip -> client -> packet.htype = ip -> hw_address.htype; ip -> client -> packet.hlen = ip -> hw_address.hlen; ip -> client -> packet.hops = 0; ip -> client -> packet.xid = ip -> client -> xid; ip -> client -> packet.secs = 0; /* Filled in by send_request. */ ip -> client -> packet.flags = 0; /* ciaddr must always be zero. */ memset (&ip -> client -> packet.ciaddr, 0, sizeof ip -> client -> packet.ciaddr); memset (&ip -> client -> packet.yiaddr, 0, sizeof ip -> client -> packet.yiaddr); memset (&ip -> client -> packet.siaddr, 0, sizeof ip -> client -> packet.siaddr); memset (&ip -> client -> packet.giaddr, 0, sizeof ip -> client -> packet.giaddr); memcpy (ip -> client -> packet.chaddr, ip -> hw_address.haddr, ip -> hw_address.hlen); #ifdef DEBUG_PACKET dump_packet (sendpkt); dump_raw ((unsigned char *)ip -> client -> packet, sendpkt->packet_length); #endif } void make_release (ip, lease) struct interface_info *ip; struct client_lease *lease; { unsigned char request = DHCPRELEASE; int i; struct tree_cache *options [256]; struct tree_cache message_type_tree; struct tree_cache server_id_tree; memset (options, 0, sizeof options); memset (&ip -> client -> packet, 0, sizeof (ip -> client -> packet)); /* Set DHCP_MESSAGE_TYPE to DHCPRELEASE */ i = DHO_DHCP_MESSAGE_TYPE; options [i] = &message_type_tree; options [i] -> value = &request; options [i] -> len = sizeof request; options [i] -> buf_size = sizeof request; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; /* Send back the server identifier... */ i = DHO_DHCP_SERVER_IDENTIFIER; options [i] = &server_id_tree; options [i] -> value = lease -> options [i].data; options [i] -> len = lease -> options [i].len; options [i] -> buf_size = lease -> options [i].len; options [i] -> timeout = 0xFFFFFFFF; options [i] -> tree = (struct tree *)0; /* Set up the option buffer... */ ip -> client -> packet_length = cons_options ((struct packet *)0, &ip -> client -> packet, 0, options, 0, 0, 0, (u_int8_t *)0, 0); if (ip -> client -> packet_length < BOOTP_MIN_LEN) ip -> client -> packet_length = BOOTP_MIN_LEN; ip -> client -> packet.op = BOOTREQUEST; ip -> client -> packet.htype = ip -> hw_address.htype; ip -> client -> packet.hlen = ip -> hw_address.hlen; ip -> client -> packet.hops = 0; ip -> client -> packet.xid = random (); ip -> client -> packet.secs = 0; ip -> client -> packet.flags = 0; memset (&ip -> client -> packet.ciaddr, 0, sizeof ip -> client -> packet.ciaddr); memset (&ip -> client -> packet.yiaddr, 0, sizeof ip -> client -> packet.yiaddr); memset (&ip -> client -> packet.siaddr, 0, sizeof ip -> client -> packet.siaddr); memset (&ip -> client -> packet.giaddr, 0, sizeof ip -> client -> packet.giaddr); memcpy (ip -> client -> packet.chaddr, ip -> hw_address.haddr, ip -> hw_address.hlen); #ifdef DEBUG_PACKET dump_packet (sendpkt); dump_raw ((unsigned char *)ip -> client -> packet, ip -> client -> packet_length); #endif } void free_client_lease (lease) struct client_lease *lease; { int i; if (lease -> server_name) free (lease -> server_name); if (lease -> filename) free (lease -> filename); for (i = 0; i < 256; i++) { if (lease -> options [i].len) free (lease -> options [i].data); } free (lease); } FILE *leaseFile; void rewrite_client_leases () { struct interface_info *ip; struct client_lease *lp; if (leaseFile) fclose (leaseFile); leaseFile = fopen (path_dhclient_db, "w"); if (!leaseFile) error ("can't create %s: %m", path_dhclient_db); /* Write out all the leases attached to configured interfaces that we know about. */ for (ip = interfaces; ip; ip = ip -> next) { for (lp = ip -> client -> leases; lp; lp = lp -> next) { write_client_lease (ip, lp, 1); } if (ip -> client -> active) write_client_lease (ip, ip -> client -> active, 1); } /* Write out any leases that are attached to interfaces that aren't currently configured. */ for (ip = dummy_interfaces; ip; ip = ip -> next) { for (lp = ip -> client -> leases; lp; lp = lp -> next) { write_client_lease (ip, lp, 1); } if (ip -> client -> active) write_client_lease (ip, ip -> client -> active, 1); } fflush (leaseFile); } void write_client_lease (ip, lease, rewrite) struct interface_info *ip; struct client_lease *lease; int rewrite; { int i; struct tm *t; static int leases_written; if (!rewrite) { if (leases_written++ > 20) { rewrite_client_leases (); leases_written = 0; } } /* If the lease came from the config file, we don't need to stash a copy in the lease database. */ if (lease -> is_static) return; if (!leaseFile) { /* XXX */ leaseFile = fopen (path_dhclient_db, "w"); if (!leaseFile) error ("can't create %s: %m", path_dhclient_db); } fprintf (leaseFile, "lease {\n"); if (lease -> is_bootp) fprintf (leaseFile, " bootp;\n"); fprintf (leaseFile, " interface \"%s\";\n", ip -> name); fprintf (leaseFile, " fixed-address %s;\n", piaddr (lease -> address)); if (lease -> filename) fprintf (leaseFile, " filename \"%s\";\n", lease -> filename); if (lease -> server_name) fprintf (leaseFile, " server-name \"%s\";\n", lease -> server_name); if (lease -> medium) fprintf (leaseFile, " medium \"%s\";\n", lease -> medium -> string); for (i = 0; i < 256; i++) { if (lease -> options [i].len) { fprintf (leaseFile, " option %s %s;\n", dhcp_options [i].name, pretty_print_option (i, lease -> options [i].data, lease -> options [i].len, 1, 1)); } } /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until somebody invents a time machine, I think we can safely disregard it. */ t = gmtime (&lease -> renewal); fprintf (leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n", t -> tm_wday, t -> tm_year + 1900, t -> tm_mon + 1, t -> tm_mday, t -> tm_hour, t -> tm_min, t -> tm_sec); t = gmtime (&lease -> rebind); fprintf (leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n", t -> tm_wday, t -> tm_year + 1900, t -> tm_mon + 1, t -> tm_mday, t -> tm_hour, t -> tm_min, t -> tm_sec); t = gmtime (&lease -> expiry); fprintf (leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n", t -> tm_wday, t -> tm_year + 1900, t -> tm_mon + 1, t -> tm_mday, t -> tm_hour, t -> tm_min, t -> tm_sec); fprintf (leaseFile, "}\n"); fflush (leaseFile); } /* Variables holding name of script and file pointer for writing to script. Needless to say, this is not reentrant - only one script can be invoked at a time. */ char scriptName [256]; FILE *scriptFile; void script_init (ip, reason, medium) struct interface_info *ip; char *reason; struct string_list *medium; { - int fd; -#ifndef HAVE_MKSTEMP - - do { -#endif - strcpy (scriptName, "/tmp/dcsXXXXXX"); -#ifdef HAVE_MKSTEMP - fd = mkstemp (scriptName); -#else - if (!mktemp (scriptName)) - error ("can't create temporary client script %s: %m", - scriptName); - fd = open (scriptName, O_EXCL | O_CREAT | O_WRONLY, 0600); - } while (fd < 0 && errno == EEXIST); -#endif - if (fd < 0) - error ("can't create temporary script %s: %m", scriptName); + struct string_list *sl, *next; - scriptFile = fdopen (fd, "w"); - if (!scriptFile) - error ("can't write script file: %m"); - fprintf (scriptFile, "#!/bin/sh\n\n"); if (ip) { - fprintf (scriptFile, "interface=\"%s\"\n", ip -> name); - fprintf (scriptFile, "export interface\n"); - } - if (medium) { - fprintf (scriptFile, "medium=\"%s\"\n", medium -> string); - fprintf (scriptFile, "export medium\n"); + for (sl = ip -> client -> env; sl; sl = next) { + next = sl -> next; + dfree (sl, "script_init"); + } + ip -> client -> env = (struct string_list *)0; + ip -> client -> envc = 0; + + client_envadd (ip -> client, "", "interface", "%s", + ip -> name); + if (medium) + client_envadd (ip -> client, + "", "medium", "%s", medium -> string); + + client_envadd (ip -> client, "", "reason", "%s", reason); } - fprintf (scriptFile, "reason=\"%s\"\n", reason); - fprintf (scriptFile, "export reason\n"); } void script_write_params (ip, prefix, lease) struct interface_info *ip; char *prefix; struct client_lease *lease; { int i; u_int8_t dbuf [1500]; int len; - fprintf (scriptFile, "%sip_address=\"%s\"\n", - prefix, piaddr (lease -> address)); - fprintf (scriptFile, "export %sip_address\n", prefix); + client_envadd (ip -> client, + prefix, "ip_address", "%s", piaddr (lease -> address)); /* For the benefit of Linux (and operating systems which may have similar needs), compute the network address based on the supplied ip address and netmask, if provided. Also compute the broadcast address (the host address all ones broadcast address, not the host address all zeroes broadcast address). */ if (lease -> options [DHO_SUBNET_MASK].len && (lease -> options [DHO_SUBNET_MASK].len < sizeof lease -> address.iabuf)) { struct iaddr netmask, subnet, broadcast; memcpy (netmask.iabuf, lease -> options [DHO_SUBNET_MASK].data, lease -> options [DHO_SUBNET_MASK].len); netmask.len = lease -> options [DHO_SUBNET_MASK].len; subnet = subnet_number (lease -> address, netmask); if (subnet.len) { - fprintf (scriptFile, "%snetwork_number=\"%s\";\n", - prefix, piaddr (subnet)); - fprintf (scriptFile, "export %snetwork_number\n", - prefix); + client_envadd (ip -> client, prefix, "network_number", + "%s", piaddr (subnet)); if (!lease -> options [DHO_BROADCAST_ADDRESS].len) { broadcast = broadcast_addr (subnet, netmask); if (broadcast.len) { - fprintf (scriptFile, - "%s%s=\"%s\";\n", prefix, - "broadcast_address", - piaddr (broadcast)); - fprintf (scriptFile, - "export %s%s\n", prefix, - "broadcast_address"); + client_envadd (ip -> client, + prefix, "broadcast_address", + "%s", piaddr (subnet)); } } } } - if (lease -> filename) { - fprintf (scriptFile, "%sfilename=\"%s\";\n", - prefix, lease -> filename); - fprintf (scriptFile, "export %sfilename\n", prefix); - } - if (lease -> server_name) { - fprintf (scriptFile, "%sserver_name=\"%s\";\n", - prefix, lease -> server_name); - fprintf (scriptFile, "export %sserver_name\n", prefix); - } + if (lease -> filename) + client_envadd (ip -> client, + prefix, "filename", "%s", lease -> filename); + if (lease -> server_name) + client_envadd (ip -> client, prefix, "server_name", + "%s", lease -> server_name); for (i = 0; i < 256; i++) { u_int8_t *dp; if (ip -> client -> config -> defaults [i].len) { if (lease -> options [i].len) { switch (ip -> client -> config -> default_actions [i]) { case ACTION_DEFAULT: dp = lease -> options [i].data; len = lease -> options [i].len; break; case ACTION_SUPERSEDE: supersede: dp = ip -> client -> config -> defaults [i].data; len = ip -> client -> config -> defaults [i].len; break; case ACTION_PREPEND: len = (ip -> client -> config -> defaults [i].len + lease -> options [i].len); if (len > sizeof dbuf) { warn ("no space to %s %s", "prepend option", dhcp_options [i].name); goto supersede; } dp = dbuf; memcpy (dp, ip -> client -> config -> defaults [i].data, ip -> client -> config -> defaults [i].len); memcpy (dp + ip -> client -> config -> defaults [i].len, lease -> options [i].data, lease -> options [i].len); break; case ACTION_APPEND: len = (ip -> client -> config -> defaults [i].len + lease -> options [i].len); if (len > sizeof dbuf) { warn ("no space to %s %s", "append option", dhcp_options [i].name); goto supersede; } dp = dbuf; memcpy (dp, lease -> options [i].data, lease -> options [i].len); memcpy (dp + lease -> options [i].len, ip -> client -> config -> defaults [i].data, ip -> client -> config -> defaults [i].len); } } else { dp = ip -> client -> config -> defaults [i].data; len = ip -> client -> config -> defaults [i].len; } } else if (lease -> options [i].len) { len = lease -> options [i].len; dp = lease -> options [i].data; } else { len = 0; } if (len) { - char *s = dhcp_option_ev_name (&dhcp_options [i]); - - fprintf (scriptFile, "%s%s=\"%s\"\n", prefix, s, - pretty_print_option (i, dp, len, 0, 0)); - fprintf (scriptFile, "export %s%s\n", prefix, s); + char name [256]; + if (dhcp_option_ev_name (name, sizeof name, + &dhcp_options [i])) { + client_envadd (ip -> client, prefix, name, "%s", + (pretty_print_option (i, dp, + len, 0, 0))); + } } } - fprintf (scriptFile, "%sexpiry=\"%d\"\n", - prefix, (int)lease -> expiry); /* XXX */ - fprintf (scriptFile, "export %sexpiry\n", prefix); + client_envadd (ip -> client, + prefix, "expiry", "%d", (int)(lease -> expiry)); } int script_go (ip) struct interface_info *ip; { int rval; + char *scriptName; + char *argv [2]; + char **envp; + char *epp [3]; + char reason [] = "REASON=NBI"; + static char client_path [] = CLIENT_PATH; + int i; + struct string_list *sp, *next; + int pid, wpid, wstatus; - if (ip) - fprintf (scriptFile, "%s\n", - ip -> client -> config -> script_name); - else - fprintf (scriptFile, "%s\n", - top_level_config.script_name); - fprintf (scriptFile, "exit $?\n"); - fclose (scriptFile); - chmod (scriptName, 0700); - rval = system (scriptName); - if (!save_scripts) - unlink (scriptName); - return rval; + if (ip) { + scriptName = ip -> client -> config -> script_name; + envp = dmalloc ((ip -> client -> envc + 2) * sizeof (char *), + "script_go"); + if (!envp) { + error ("No memory for client script environment."); + return 0; + } + i = 0; + for (sp = ip -> client -> env; sp; sp = sp -> next) { + envp [i++] = sp -> string; + } + envp [i++] = client_path; + envp [i] = (char *)0; + } else { + scriptName = top_level_config.script_name; + epp [0] = reason; + epp [1] = client_path; + epp [2] = (char *)0; + envp = epp; + } + + argv [0] = scriptName; + argv [1] = (char *)0; + + pid = fork (); + if (pid < 0) { + error ("fork: %m"); + wstatus = 0; + } else if (pid) { + do { + wpid = wait (&wstatus); + } while (wpid != pid && wpid > 0); + if (wpid < 0) { + error ("wait: %m"); + wstatus = 0; + } + } else { + execve (scriptName, argv, envp); + error ("execve (%s, ...): %m", scriptName); + exit (0); + } + + if (ip) { + for (sp = ip -> client -> env; sp; sp = next) { + next = sp -> next; + dfree (sp, "script_go"); + } + ip -> client -> env = (struct string_list *)0; + ip -> client -> envc = 0; + dfree (envp, "script_go"); + } + return wstatus & 0xff; } -char *dhcp_option_ev_name (option) +void client_envadd (struct client_state *client, + const char *prefix, const char *name, const char *fmt, ...) +{ + char spbuf [1024]; + char *s; + unsigned len, i; + struct string_list *val; + va_list list; + + va_start (list, fmt); + len = vsnprintf (spbuf, sizeof spbuf, fmt, list); + va_end (list); + + val = dmalloc (strlen (prefix) + strlen (name) + 1 /* = */ + + len + sizeof *val, "client_envadd"); + if (!val) + return; + s = val -> string; + strcpy (s, prefix); + strcat (s, name); + s += strlen (s); + *s++ = '='; + if (len >= sizeof spbuf) { + va_start (list, fmt); + vsnprintf (s, len + 1, fmt, list); + va_end (list); + } else + strcpy (s, spbuf); + val -> next = client -> env; + client -> env = val; + client -> envc++; +} + +int dhcp_option_ev_name (buf, buflen, option) + char *buf; + unsigned buflen; struct option *option; { - static char evbuf [256]; int i; - if (strlen (option -> name) + 1 > sizeof evbuf) - error ("option %s name is larger than static buffer."); for (i = 0; option -> name [i]; i++) { + if (i + 1 == buflen) + return 0; if (option -> name [i] == '-') - evbuf [i] = '_'; + buf [i] = '_'; else - evbuf [i] = option -> name [i]; + buf [i] = option -> name [i]; } - evbuf [i] = 0; - return evbuf; + buf [i] = 0; + return 1; } - + void go_daemon () { static int state = 0; int pid; /* Don't become a daemon if the user requested otherwise. */ if (no_daemon) { write_client_pid_file (); return; } /* Only do it once. */ if (state) return; state = 1; /* Stop logging to stderr... */ log_perror = 0; /* Become a daemon... */ if ((pid = fork ()) < 0) error ("Can't fork daemon: %m"); else if (pid) exit (0); /* Become session leader and get pid... */ pid = setsid (); /* Close standard I/O descriptors. */ close(0); close(1); close(2); write_client_pid_file (); } void write_client_pid_file () { FILE *pf; int pfdesc; pfdesc = open (path_dhclient_pid, O_CREAT | O_TRUNC | O_WRONLY, 0644); if (pfdesc < 0) { warn ("Can't create %s: %m", path_dhclient_pid); return; } pf = fdopen (pfdesc, "w"); if (!pf) warn ("Can't fdopen %s: %m", path_dhclient_pid); else { fprintf (pf, "%ld\n", (long)getpid ()); fclose (pf); } } diff --git a/contrib/isc-dhcp/includes/dhcpd.h b/contrib/isc-dhcp/includes/dhcpd.h index ddf34f0ef154..d46ddf1bfae5 100644 --- a/contrib/isc-dhcp/includes/dhcpd.h +++ b/contrib/isc-dhcp/includes/dhcpd.h @@ -1,1035 +1,1040 @@ /* dhcpd.h Definitions for dhcpd... */ /* * Copyright (c) 1995, 1996, 1997, 1998, 1999 * The Internet Software Consortium. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. */ #ifndef __CYGWIN32__ #include #include #include #include #include #include #else #define fd_set cygwin_fd_set #include #endif #include #include #include #include #include #include #include #include #include "cdefs.h" #include "osdep.h" #include "dhcp.h" #include "tree.h" #include "hash.h" #include "inet.h" #include "sysconf.h" struct option_data { int len; u_int8_t *data; }; struct string_list { struct string_list *next; char string [1]; }; /* A name server, from /etc/resolv.conf. */ struct name_server { struct name_server *next; struct sockaddr_in addr; TIME rcdate; }; /* A domain search list element. */ struct domain_search_list { struct domain_search_list *next; char *domain; TIME rcdate; }; /* A dhcp packet and the pointers to its option values. */ struct packet { struct dhcp_packet *raw; int packet_length; int packet_type; int options_valid; int client_port; struct iaddr client_addr; struct interface_info *interface; /* Interface on which packet was received. */ struct hardware *haddr; /* Physical link address of local sender (maybe gateway). */ struct shared_network *shared_network; struct option_data options [256]; int got_requested_address; /* True if client sent the dhcp-requested-address option. */ }; struct hardware { u_int8_t htype; u_int8_t hlen; u_int8_t haddr [16]; }; /* A dhcp lease declaration structure. */ struct lease { struct lease *next; struct lease *prev; struct lease *n_uid, *n_hw; struct lease *waitq_next; struct iaddr ip_addr; TIME starts, ends, timestamp; unsigned char *uid; int uid_len; int uid_max; unsigned char uid_buf [32]; char *hostname; char *client_hostname; struct host_decl *host; struct subnet *subnet; struct shared_network *shared_network; struct hardware hardware_addr; int flags; # define STATIC_LEASE 1 # define BOOTP_LEASE 2 # define DYNAMIC_BOOTP_OK 4 # define PERSISTENT_FLAGS (DYNAMIC_BOOTP_OK) # define EPHEMERAL_FLAGS (BOOTP_LEASE) # define MS_NULL_TERMINATION 8 # define ABANDONED_LEASE 16 struct lease_state *state; }; struct lease_state { struct lease_state *next; struct interface_info *ip; TIME offered_expiry; struct tree_cache *options [256]; u_int32_t expiry, renewal, rebind; char filename [DHCP_FILE_LEN]; char *server_name; struct iaddr from; int max_message_size; u_int8_t *prl; int prl_len; int got_requested_address; /* True if client sent the dhcp-requested-address option. */ int got_server_identifier; /* True if client sent the dhcp-server-identifier option. */ struct shared_network *shared_network; /* Shared network of interface on which request arrived. */ u_int32_t xid; u_int16_t secs; u_int16_t bootp_flags; struct in_addr ciaddr; struct in_addr giaddr; u_int8_t hops; u_int8_t offer; }; #define ROOT_GROUP 0 #define HOST_DECL 1 #define SHARED_NET_DECL 2 #define SUBNET_DECL 3 #define CLASS_DECL 4 #define GROUP_DECL 5 /* Possible modes in which discover_interfaces can run. */ #define DISCOVER_RUNNING 0 #define DISCOVER_SERVER 1 #define DISCOVER_UNCONFIGURED 2 #define DISCOVER_RELAY 3 #define DISCOVER_REQUESTED 4 /* Group of declarations that share common parameters. */ struct group { struct group *next; struct subnet *subnet; struct shared_network *shared_network; TIME default_lease_time; TIME max_lease_time; TIME bootp_lease_cutoff; TIME bootp_lease_length; char *filename; char *server_name; struct iaddr next_server; int boot_unknown_clients; int dynamic_bootp; int allow_bootp; int allow_booting; int one_lease_per_client; int get_lease_hostnames; int use_host_decl_names; int use_lease_addr_for_default_route; int authoritative; int always_reply_rfc1048; struct tree_cache *options [256]; }; /* A dhcp host declaration structure. */ struct host_decl { struct host_decl *n_ipaddr; char *name; struct hardware interface; struct tree_cache *fixed_addr; struct group *group; }; struct shared_network { struct shared_network *next; char *name; struct subnet *subnets; struct interface_info *interface; struct lease *leases; struct lease *insertion_point; struct lease *last_lease; struct group *group; }; struct subnet { struct subnet *next_subnet; struct subnet *next_sibling; struct shared_network *shared_network; struct interface_info *interface; struct iaddr interface_address; struct iaddr net; struct iaddr netmask; struct group *group; }; struct class { char *name; struct group *group; }; /* DHCP client lease structure... */ struct client_lease { struct client_lease *next; /* Next lease in list. */ TIME expiry, renewal, rebind; /* Lease timeouts. */ struct iaddr address; /* Address being leased. */ char *server_name; /* Name of boot server. */ char *filename; /* Name of file we're supposed to boot. */ struct string_list *medium; /* Network medium. */ unsigned int is_static : 1; /* If set, lease is from config file. */ unsigned int is_bootp: 1; /* If set, lease was aquired with BOOTP. */ struct option_data options [256]; /* Options supplied with lease. */ }; /* Possible states in which the client can be. */ enum dhcp_state { S_REBOOTING, S_INIT, S_SELECTING, S_REQUESTING, S_BOUND, S_RENEWING, S_REBINDING }; /* Configuration information from the config file... */ struct client_config { struct option_data defaults [256]; /* Default values for options. */ enum { ACTION_DEFAULT, /* Use server value if present, otherwise default. */ ACTION_SUPERSEDE, /* Always use default. */ ACTION_PREPEND, /* Prepend default to server. */ ACTION_APPEND, /* Append default to server. */ } default_actions [256]; struct option_data send_options [256]; /* Send these to server. */ u_int8_t required_options [256]; /* Options server must supply. */ u_int8_t requested_options [256]; /* Options to request from server. */ int requested_option_count; /* Number of requested options. */ TIME timeout; /* Start to panic if we don't get a lease in this time period when SELECTING. */ TIME initial_interval; /* All exponential backoff intervals start here. */ TIME retry_interval; /* If the protocol failed to produce an address before the timeout, try the protocol again after this many seconds. */ TIME select_interval; /* Wait this many seconds from the first DHCPDISCOVER before picking an offered lease. */ TIME reboot_timeout; /* When in INIT-REBOOT, wait this long before giving up and going to INIT. */ TIME backoff_cutoff; /* When doing exponential backoff, never back off to an interval longer than this amount. */ struct string_list *media; /* Possible network media values. */ char *script_name; /* Name of config script. */ enum { IGNORE, ACCEPT, PREFER } bootp_policy; /* Ignore, accept or prefer BOOTP responses. */ struct string_list *medium; /* Current network medium. */ struct iaddrlist *reject_list; /* Servers to reject. */ }; /* Per-interface state used in the dhcp client... */ struct client_state { struct client_lease *active; /* Currently active lease. */ struct client_lease *new; /* New lease. */ struct client_lease *offered_leases; /* Leases offered to us. */ struct client_lease *leases; /* Leases we currently hold. */ struct client_lease *alias; /* Alias lease. */ enum dhcp_state state; /* Current state for this interface. */ struct iaddr destination; /* Where to send packet. */ u_int32_t xid; /* Transaction ID. */ u_int16_t secs; /* secs value from DHCPDISCOVER. */ TIME first_sending; /* When was first copy sent? */ TIME interval; /* What's the current resend interval? */ struct string_list *medium; /* Last media type tried. */ struct dhcp_packet packet; /* Outgoing DHCP packet. */ int packet_length; /* Actual length of generated packet. */ struct iaddr requested_address; /* Address we would like to get. */ struct client_config *config; /* Information from config file. */ + + struct string_list *env; /* Client script environment. */ + int envc; /* Number of entries in environment. */ }; /* Information about each network interface. */ struct interface_info { struct interface_info *next; /* Next interface in list... */ struct shared_network *shared_network; /* Networks connected to this interface. */ struct hardware hw_address; /* Its physical address. */ struct in_addr primary_address; /* Primary interface address. */ char name [IFNAMSIZ]; /* Its name... */ int rfdesc; /* Its read file descriptor. */ int wfdesc; /* Its write file descriptor, if different. */ unsigned char *rbuf; /* Read buffer, if required. */ size_t rbuf_max; /* Size of read buffer. */ size_t rbuf_offset; /* Current offset into buffer. */ size_t rbuf_len; /* Length of data in buffer. */ struct ifreq *ifp; /* Pointer to ifreq struct. */ u_int32_t flags; /* Control flags... */ #define INTERFACE_REQUESTED 1 #define INTERFACE_AUTOMATIC 2 /* Only used by DHCP client code. */ struct client_state *client; }; struct hardware_link { struct hardware_link *next; char name [IFNAMSIZ]; struct hardware address; }; struct timeout { struct timeout *next; TIME when; void (*func) PROTO ((void *)); void *what; }; struct protocol { struct protocol *next; int fd; void (*handler) PROTO ((struct protocol *)); void *local; }; /* Bitmask of dhcp option codes. */ typedef unsigned char option_mask [16]; /* DHCP Option mask manipulation macros... */ #define OPTION_ZERO(mask) (memset (mask, 0, 16)) #define OPTION_SET(mask, bit) (mask [bit >> 8] |= (1 << (bit & 7))) #define OPTION_CLR(mask, bit) (mask [bit >> 8] &= ~(1 << (bit & 7))) #define OPTION_ISSET(mask, bit) (mask [bit >> 8] & (1 << (bit & 7))) #define OPTION_ISCLR(mask, bit) (!OPTION_ISSET (mask, bit)) /* An option occupies its length plus two header bytes (code and length) for every 255 bytes that must be stored. */ #define OPTION_SPACE(x) ((x) + 2 * ((x) / 255 + 1)) /* Default path to dhcpd config file. */ #ifdef DEBUG #undef _PATH_DHCPD_CONF #define _PATH_DHCPD_CONF "dhcpd.conf" #undef _PATH_DHCPD_DB #define _PATH_DHCPD_DB "dhcpd.leases" #else #ifndef _PATH_DHCPD_CONF #define _PATH_DHCPD_CONF "/etc/dhcpd.conf" #endif #ifndef _PATH_DHCPD_DB #define _PATH_DHCPD_DB "/etc/dhcpd.leases" #endif #ifndef _PATH_DHCPD_PID #define _PATH_DHCPD_PID "/var/run/dhcpd.pid" #endif #endif #ifndef _PATH_DHCLIENT_CONF #define _PATH_DHCLIENT_CONF "/etc/dhclient.conf" #endif #ifndef _PATH_DHCLIENT_PID #define _PATH_DHCLIENT_PID "/var/run/dhclient.pid" #endif #ifndef _PATH_DHCLIENT_DB #define _PATH_DHCLIENT_DB "/etc/dhclient.leases" #endif #ifndef _PATH_RESOLV_CONF #define _PATH_RESOLV_CONF "/etc/resolv.conf" #endif #ifndef _PATH_DHCRELAY_PID #define _PATH_DHCRELAY_PID "/var/run/dhcrelay.pid" #endif #ifndef DHCPD_LOG_FACILITY #define DHCPD_LOG_FACILITY LOG_DAEMON #endif #define MAX_TIME 0x7fffffff #define MIN_TIME 0 /* External definitions... */ /* options.c */ void parse_options PROTO ((struct packet *)); void parse_option_buffer PROTO ((struct packet *, unsigned char *, int)); int cons_options PROTO ((struct packet *, struct dhcp_packet *, int, struct tree_cache **, int, int, int, u_int8_t *, int)); int store_options PROTO ((unsigned char *, int, struct tree_cache **, unsigned char *, int, int, int, int)); char *pretty_print_option PROTO ((unsigned int, unsigned char *, int, int, int)); void do_packet PROTO ((struct interface_info *, struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *)); /* errwarn.c */ extern int warnings_occurred; void error PROTO ((char *, ...)); int warn PROTO ((char *, ...)); int note PROTO ((char *, ...)); int debug PROTO ((char *, ...)); int parse_warn PROTO ((char *, ...)); /* dhcpd.c */ extern TIME cur_time; extern struct group root_group; extern u_int16_t local_port; extern u_int16_t remote_port; extern int log_priority; extern int log_perror; extern char *path_dhcpd_conf; extern char *path_dhcpd_db; extern char *path_dhcpd_pid; int main PROTO ((int, char **, char **)); void cleanup PROTO ((void)); void lease_pinged PROTO ((struct iaddr, u_int8_t *, int)); void lease_ping_timeout PROTO ((void *)); /* conflex.c */ extern int lexline, lexchar; extern char *token_line, *tlname; extern char comments [4096]; extern int comment_index; extern int eol_token; void new_parse PROTO ((char *)); int next_token PROTO ((char **, FILE *)); int peek_token PROTO ((char **, FILE *)); /* confpars.c */ int readconf PROTO ((void)); void read_leases PROTO ((void)); int parse_statement PROTO ((FILE *, struct group *, int, struct host_decl *, int)); void parse_allow_deny PROTO ((FILE *, struct group *, int)); void skip_to_semi PROTO ((FILE *)); int parse_boolean PROTO ((FILE *)); int parse_semi PROTO ((FILE *)); int parse_lbrace PROTO ((FILE *)); void parse_host_declaration PROTO ((FILE *, struct group *)); char *parse_host_name PROTO ((FILE *)); void parse_class_declaration PROTO ((FILE *, struct group *, int)); void parse_lease_time PROTO ((FILE *, TIME *)); void parse_shared_net_declaration PROTO ((FILE *, struct group *)); void parse_subnet_declaration PROTO ((FILE *, struct shared_network *)); void parse_group_declaration PROTO ((FILE *, struct group *)); void parse_hardware_param PROTO ((FILE *, struct hardware *)); char *parse_string PROTO ((FILE *)); struct tree *parse_ip_addr_or_hostname PROTO ((FILE *, int)); struct tree_cache *parse_fixed_addr_param PROTO ((FILE *)); void parse_option_param PROTO ((FILE *, struct group *)); TIME parse_timestamp PROTO ((FILE *)); struct lease *parse_lease_declaration PROTO ((FILE *)); void parse_address_range PROTO ((FILE *, struct subnet *)); TIME parse_date PROTO ((FILE *)); unsigned char *parse_numeric_aggregate PROTO ((FILE *, unsigned char *, int *, int, int, int)); void convert_num PROTO ((unsigned char *, char *, int, int)); /* tree.c */ pair cons PROTO ((caddr_t, pair)); struct tree_cache *tree_cache PROTO ((struct tree *)); struct tree *tree_host_lookup PROTO ((char *)); struct dns_host_entry *enter_dns_host PROTO ((char *)); struct tree *tree_const PROTO ((unsigned char *, int)); struct tree *tree_concat PROTO ((struct tree *, struct tree *)); struct tree *tree_limit PROTO ((struct tree *, int)); int tree_evaluate PROTO ((struct tree_cache *)); /* dhcp.c */ extern int outstanding_pings; void dhcp PROTO ((struct packet *)); void dhcpdiscover PROTO ((struct packet *)); void dhcprequest PROTO ((struct packet *)); void dhcprelease PROTO ((struct packet *)); void dhcpdecline PROTO ((struct packet *)); void dhcpinform PROTO ((struct packet *)); void nak_lease PROTO ((struct packet *, struct iaddr *cip)); void ack_lease PROTO ((struct packet *, struct lease *, unsigned int, TIME)); void dhcp_reply PROTO ((struct lease *)); struct lease *find_lease PROTO ((struct packet *, struct shared_network *, int *)); struct lease *mockup_lease PROTO ((struct packet *, struct shared_network *, struct host_decl *)); /* bootp.c */ void bootp PROTO ((struct packet *)); /* memory.c */ void enter_host PROTO ((struct host_decl *)); struct host_decl *find_hosts_by_haddr PROTO ((int, unsigned char *, int)); struct host_decl *find_hosts_by_uid PROTO ((unsigned char *, int)); struct subnet *find_host_for_network PROTO ((struct host_decl **, struct iaddr *, struct shared_network *)); void new_address_range PROTO ((struct iaddr, struct iaddr, struct subnet *, int)); extern struct subnet *find_grouped_subnet PROTO ((struct shared_network *, struct iaddr)); extern struct subnet *find_subnet PROTO ((struct iaddr)); void enter_shared_network PROTO ((struct shared_network *)); int subnet_inner_than PROTO ((struct subnet *, struct subnet *, int)); void enter_subnet PROTO ((struct subnet *)); void enter_lease PROTO ((struct lease *)); int supersede_lease PROTO ((struct lease *, struct lease *, int)); void release_lease PROTO ((struct lease *)); void abandon_lease PROTO ((struct lease *, char *)); struct lease *find_lease_by_uid PROTO ((unsigned char *, int)); struct lease *find_lease_by_hw_addr PROTO ((unsigned char *, int)); struct lease *find_lease_by_ip_addr PROTO ((struct iaddr)); void uid_hash_add PROTO ((struct lease *)); void uid_hash_delete PROTO ((struct lease *)); void hw_hash_add PROTO ((struct lease *)); void hw_hash_delete PROTO ((struct lease *)); struct class *add_class PROTO ((int, char *)); struct class *find_class PROTO ((int, unsigned char *, int)); struct group *clone_group PROTO ((struct group *, char *)); void write_leases PROTO ((void)); void dump_subnets PROTO ((void)); /* alloc.c */ VOIDPTR dmalloc PROTO ((int, char *)); void dfree PROTO ((VOIDPTR, char *)); struct packet *new_packet PROTO ((char *)); struct dhcp_packet *new_dhcp_packet PROTO ((char *)); struct tree *new_tree PROTO ((char *)); struct tree_cache *new_tree_cache PROTO ((char *)); struct hash_table *new_hash_table PROTO ((int, char *)); struct hash_bucket *new_hash_bucket PROTO ((char *)); struct lease *new_lease PROTO ((char *)); struct lease *new_leases PROTO ((int, char *)); struct subnet *new_subnet PROTO ((char *)); struct class *new_class PROTO ((char *)); struct shared_network *new_shared_network PROTO ((char *)); struct group *new_group PROTO ((char *)); struct protocol *new_protocol PROTO ((char *)); struct lease_state *new_lease_state PROTO ((char *)); struct domain_search_list *new_domain_search_list PROTO ((char *)); struct name_server *new_name_server PROTO ((char *)); void free_name_server PROTO ((struct name_server *, char *)); void free_domain_search_list PROTO ((struct domain_search_list *, char *)); void free_lease_state PROTO ((struct lease_state *, char *)); void free_protocol PROTO ((struct protocol *, char *)); void free_group PROTO ((struct group *, char *)); void free_shared_network PROTO ((struct shared_network *, char *)); void free_class PROTO ((struct class *, char *)); void free_subnet PROTO ((struct subnet *, char *)); void free_lease PROTO ((struct lease *, char *)); void free_hash_bucket PROTO ((struct hash_bucket *, char *)); void free_hash_table PROTO ((struct hash_table *, char *)); void free_tree_cache PROTO ((struct tree_cache *, char *)); void free_packet PROTO ((struct packet *, char *)); void free_dhcp_packet PROTO ((struct dhcp_packet *, char *)); void free_tree PROTO ((struct tree *, char *)); /* print.c */ char *print_hw_addr PROTO ((int, int, unsigned char *)); void print_lease PROTO ((struct lease *)); void dump_raw PROTO ((unsigned char *, int)); void dump_packet PROTO ((struct packet *)); void hash_dump PROTO ((struct hash_table *)); /* socket.c */ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \ || defined (USE_SOCKET_FALLBACK) int if_register_socket PROTO ((struct interface_info *)); #endif #if defined (USE_SOCKET_FALLBACK) && !defined (USE_SOCKET_SEND) void if_reinitialize_fallback PROTO ((struct interface_info *)); void if_register_fallback PROTO ((struct interface_info *)); ssize_t send_fallback PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); #endif #ifdef USE_SOCKET_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); #endif #if defined (USE_SOCKET_FALLBACK) void fallback_discard PROTO ((struct protocol *)); #endif #ifdef USE_SOCKET_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif #if defined (USE_SOCKET_SEND) int can_unicast_without_arp PROTO ((void)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); void maybe_setup_fallback PROTO ((void)); #endif /* bpf.c */ #if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) int if_register_bpf PROTO ( (struct interface_info *)); #endif #ifdef USE_BPF_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); #endif #ifdef USE_BPF_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif #if defined (USE_BPF_SEND) int can_unicast_without_arp PROTO ((void)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); void maybe_setup_fallback PROTO ((void)); #endif /* lpf.c */ #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE) int if_register_lpf PROTO ( (struct interface_info *)); #endif #ifdef USE_LPF_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); #endif #ifdef USE_LPF_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif #if defined (USE_LPF_SEND) int can_unicast_without_arp PROTO ((void)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); void maybe_setup_fallback PROTO ((void)); #endif /* nit.c */ #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE) int if_register_nit PROTO ( (struct interface_info *)); #endif #ifdef USE_NIT_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); #endif #ifdef USE_NIT_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif #if defined (USE_NIT_SEND) int can_unicast_without_arp PROTO ((void)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); void maybe_setup_fallback PROTO ((void)); #endif #ifdef USE_DLPI_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); #endif #ifdef USE_DLPI_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); void if_register_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); #endif #if defined (USE_DLPI_SEND) int can_unicast_without_arp PROTO ((void)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); void maybe_setup_fallback PROTO ((void)); #endif /* raw.c */ #ifdef USE_RAW_SEND void if_reinitialize_send PROTO ((struct interface_info *)); void if_register_send PROTO ((struct interface_info *)); ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); int can_unicast_without_arp PROTO ((void)); int can_receive_unicast_unconfigured PROTO ((struct interface_info *)); void maybe_setup_fallback PROTO ((void)); #endif /* dispatch.c */ extern struct interface_info *interfaces, *dummy_interfaces, *fallback_interface; extern struct protocol *protocols; extern int quiet_interface_discovery; extern void (*bootp_packet_handler) PROTO ((struct interface_info *, struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *)); extern struct timeout *timeouts; void discover_interfaces PROTO ((int)); struct interface_info *setup_fallback PROTO ((void)); void reinitialize_interfaces PROTO ((void)); void dispatch PROTO ((void)); int locate_network PROTO ((struct packet *)); void got_one PROTO ((struct protocol *)); void add_timeout PROTO ((TIME, void (*) PROTO ((void *)), void *)); void cancel_timeout PROTO ((void (*) PROTO ((void *)), void *)); void add_protocol PROTO ((char *, int, void (*) PROTO ((struct protocol *)), void *)); void remove_protocol PROTO ((struct protocol *)); /* hash.c */ struct hash_table *new_hash PROTO ((void)); void add_hash PROTO ((struct hash_table *, unsigned char *, int, unsigned char *)); void delete_hash_entry PROTO ((struct hash_table *, unsigned char *, int)); unsigned char *hash_lookup PROTO ((struct hash_table *, unsigned char *, int)); /* tables.c */ extern struct option dhcp_options [256]; extern unsigned char dhcp_option_default_priority_list []; extern int sizeof_dhcp_option_default_priority_list; extern char *hardware_types [256]; extern struct hash_table universe_hash; extern struct universe dhcp_universe; void initialize_universes PROTO ((void)); /* convert.c */ u_int32_t getULong PROTO ((unsigned char *)); int32_t getLong PROTO ((unsigned char *)); u_int16_t getUShort PROTO ((unsigned char *)); int16_t getShort PROTO ((unsigned char *)); void putULong PROTO ((unsigned char *, u_int32_t)); void putLong PROTO ((unsigned char *, int32_t)); void putUShort PROTO ((unsigned char *, unsigned int)); void putShort PROTO ((unsigned char *, int)); /* inet.c */ struct iaddr subnet_number PROTO ((struct iaddr, struct iaddr)); struct iaddr ip_addr PROTO ((struct iaddr, struct iaddr, u_int32_t)); struct iaddr broadcast_addr PROTO ((struct iaddr, struct iaddr)); u_int32_t host_addr PROTO ((struct iaddr, struct iaddr)); int addr_eq PROTO ((struct iaddr, struct iaddr)); char *piaddr PROTO ((struct iaddr)); /* dhclient.c */ extern char *path_dhclient_conf; extern char *path_dhclient_db; extern char *path_dhclient_pid; extern int interfaces_requested; extern struct client_config top_level_config; void dhcpoffer PROTO ((struct packet *)); void dhcpack PROTO ((struct packet *)); void dhcpnak PROTO ((struct packet *)); void send_discover PROTO ((void *)); void send_request PROTO ((void *)); void send_release PROTO ((void *)); void send_decline PROTO ((void *)); void state_reboot PROTO ((void *)); void state_init PROTO ((void *)); void state_selecting PROTO ((void *)); void state_requesting PROTO ((void *)); void state_bound PROTO ((void *)); void state_panic PROTO ((void *)); void bind_lease PROTO ((struct interface_info *)); void make_discover PROTO ((struct interface_info *, struct client_lease *)); void make_request PROTO ((struct interface_info *, struct client_lease *)); void make_decline PROTO ((struct interface_info *, struct client_lease *)); void make_release PROTO ((struct interface_info *, struct client_lease *)); void free_client_lease PROTO ((struct client_lease *)); void rewrite_client_leases PROTO ((void)); void write_client_lease PROTO ((struct interface_info *, struct client_lease *, int)); -char *dhcp_option_ev_name PROTO ((struct option *)); void script_init PROTO ((struct interface_info *, char *, struct string_list *)); void script_write_params PROTO ((struct interface_info *, char *, struct client_lease *)); int script_go PROTO ((struct interface_info *)); +void client_envadd PROTO ((struct client_state *, + const char *, const char *, const char *, ...)); +int dhcp_option_ev_name (char *, size_t, struct option *); struct client_lease *packet_to_lease PROTO ((struct packet *)); void go_daemon PROTO ((void)); void write_client_pid_file PROTO ((void)); void status_message PROTO ((struct sysconf_header *, void *)); void client_location_changed PROTO ((void)); /* db.c */ int write_lease PROTO ((struct lease *)); int commit_leases PROTO ((void)); void db_startup PROTO ((void)); void new_lease_file PROTO ((void)); /* packet.c */ u_int32_t checksum PROTO ((unsigned char *, int, u_int32_t)); u_int32_t wrapsum PROTO ((u_int32_t)); void assemble_hw_header PROTO ((struct interface_info *, unsigned char *, int *, struct hardware *)); void assemble_udp_ip_header PROTO ((struct interface_info *, unsigned char *, int *, u_int32_t, u_int32_t, unsigned int, unsigned char *, int)); ssize_t decode_hw_header PROTO ((struct interface_info *, unsigned char *, int, struct hardware *)); ssize_t decode_udp_ip_header PROTO ((struct interface_info *, unsigned char *, int, struct sockaddr_in *, unsigned char *, int)); /* ethernet.c */ void assemble_ethernet_header PROTO ((struct interface_info *, unsigned char *, int *, struct hardware *)); ssize_t decode_ethernet_header PROTO ((struct interface_info *, unsigned char *, int, struct hardware *)); /* tr.c */ void assemble_tr_header PROTO ((struct interface_info *, unsigned char *, int *, struct hardware *)); ssize_t decode_tr_header PROTO ((struct interface_info *, unsigned char *, int, struct hardware *)); /* dhxpxlt.c */ void convert_statement PROTO ((FILE *)); void convert_host_statement PROTO ((FILE *, jrefproto)); void convert_host_name PROTO ((FILE *, jrefproto)); void convert_class_statement PROTO ((FILE *, jrefproto, int)); void convert_class_decl PROTO ((FILE *, jrefproto)); void convert_lease_time PROTO ((FILE *, jrefproto, char *)); void convert_shared_net_statement PROTO ((FILE *, jrefproto)); void convert_subnet_statement PROTO ((FILE *, jrefproto)); void convert_subnet_decl PROTO ((FILE *, jrefproto)); void convert_host_decl PROTO ((FILE *, jrefproto)); void convert_hardware_decl PROTO ((FILE *, jrefproto)); void convert_hardware_addr PROTO ((FILE *, jrefproto)); void convert_filename_decl PROTO ((FILE *, jrefproto)); void convert_servername_decl PROTO ((FILE *, jrefproto)); void convert_ip_addr_or_hostname PROTO ((FILE *, jrefproto, int)); void convert_fixed_addr_decl PROTO ((FILE *, jrefproto)); void convert_option_decl PROTO ((FILE *, jrefproto)); void convert_timestamp PROTO ((FILE *, jrefproto)); void convert_lease_statement PROTO ((FILE *, jrefproto)); void convert_address_range PROTO ((FILE *, jrefproto)); void convert_date PROTO ((FILE *, jrefproto, char *)); void convert_numeric_aggregate PROTO ((FILE *, jrefproto, int, int, int, int)); void indent PROTO ((int)); /* route.c */ void add_route_direct PROTO ((struct interface_info *, struct in_addr)); void add_route_net PROTO ((struct interface_info *, struct in_addr, struct in_addr)); void add_route_default_gateway PROTO ((struct interface_info *, struct in_addr)); void remove_routes PROTO ((struct in_addr)); void remove_if_route PROTO ((struct interface_info *, struct in_addr)); void remove_all_if_routes PROTO ((struct interface_info *)); void set_netmask PROTO ((struct interface_info *, struct in_addr)); void set_broadcast_addr PROTO ((struct interface_info *, struct in_addr)); void set_ip_address PROTO ((struct interface_info *, struct in_addr)); /* clparse.c */ int read_client_conf PROTO ((void)); void read_client_leases PROTO ((void)); void parse_client_statement PROTO ((FILE *, struct interface_info *, struct client_config *)); int parse_X PROTO ((FILE *, u_int8_t *, int)); int parse_option_list PROTO ((FILE *, u_int8_t *)); void parse_interface_declaration PROTO ((FILE *, struct client_config *)); struct interface_info *interface_or_dummy PROTO ((char *)); void make_client_state PROTO ((struct interface_info *)); void make_client_config PROTO ((struct interface_info *, struct client_config *)); void parse_client_lease_statement PROTO ((FILE *, int)); void parse_client_lease_declaration PROTO ((FILE *, struct client_lease *, struct interface_info **)); struct option *parse_option_decl PROTO ((FILE *, struct option_data *)); void parse_string_list PROTO ((FILE *, struct string_list **, int)); int parse_ip_addr PROTO ((FILE *, struct iaddr *)); void parse_reject_statement PROTO ((FILE *, struct client_config *)); /* dhcrelay.c */ void relay PROTO ((struct interface_info *, struct dhcp_packet *, int, unsigned int, struct iaddr, struct hardware *)); /* icmp.c */ void icmp_startup PROTO ((int, void (*) PROTO ((struct iaddr, u_int8_t *, int)))); int icmp_echorequest PROTO ((struct iaddr *)); void icmp_echoreply PROTO ((struct protocol *)); /* dns.c */ void dns_startup PROTO ((void)); int ns_inaddr_lookup PROTO ((u_int16_t, struct iaddr)); void dns_packet PROTO ((struct protocol *)); /* resolv.c */ extern char path_resolv_conf []; struct name_server *name_servers; struct domain_search_list *domains; void read_resolv_conf PROTO ((TIME)); struct sockaddr_in *pick_name_server PROTO ((void)); /* inet_addr.c */ #ifdef NEED_INET_ATON int inet_aton PROTO ((const char *, struct in_addr *)); #endif /* sysconf.c */ void sysconf_startup PROTO ((void (*) (struct sysconf_header *, void *))); void sysconf_restart PROTO ((void *)); void sysconf_message PROTO ((struct protocol *proto)); diff --git a/contrib/isc-dhcp/includes/version.h b/contrib/isc-dhcp/includes/version.h index ccda68fa1618..70d3d0675177 100644 --- a/contrib/isc-dhcp/includes/version.h +++ b/contrib/isc-dhcp/includes/version.h @@ -1,3 +1,3 @@ /* Current version of ISC DHCP Distribution. */ -#define DHCP_VERSION "2.0pl2" +#define DHCP_VERSION "2.0pl3"