RELEASE NOTES
April 6 2010

These are the release notes for this version of CMU+PRINCETON dhcpd.
The changes that are part of the latest Princeton patch appear first;
changes from previous Princeton patches appear afterwards, in reverse
chronological order.


=========================================================================

Princeton patch 11
April 6 2010

UPDATING FROM PATCHLEVEL 10

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patches 1, 2, 3, 4, 5, 6, 7, 8, 9, and 10 already applied.

Assuming you have already applied the previous patches, you can apply
this patch as follows:

0. Since this patch introduces new behavior as well as bug fixes, review the
   "WHAT'S CHANGED" section below before proceeding.


1. Make a record of any local customizations you have made to the product, such
   as changes you have made to 'Makefile' (or possibly 'Makefile.in') and
   'defaults.h'. If you did customize either 'Makefile.in' or 'defaults.h'
   files, put the original version back to ensure the patch will apply cleanly.


2. Change to the directory containing the dhcpd source, and feed the patch file
   to the 'patch' program. (The 'patch' program is not supplied here; it is
   included with many operating systems, and is freely available from many
   software libraries.) E.g. using GNU patch: 

   patch -p0 < CMU-dhcpd-3.3.7-PU-patch11

3. Please check for, and remove, any of the following obsolete files you find 
   ('patch' may have removed them for you):

   ./configure.in
   ./install.sh


4. Fix permissions that 'patch' was unable to do:

   chmod +x tools/dhcp-bindings-tool


5. Run 'make distclean' to remove old object files, Makefiles and
   configuration info.


6. If you had previously customized any 'Makefile.in' files (as opposed to
   customizing any 'Makefile' files) , now's the time to re-apply your
   customizations if necessary. (You *did* make a record of them, right?)

   Most of the definitions that used to be in Makefile.in have moved to 
   defaults.h, so you may not need to make any changes to any 'Makefile.in' 
   files at this time.

   Before re-apply any of your old customizations, first check to see if you can
   now accomplish what you need with a commandline option instead of a
   compile-time definition; most defaults and features that once required a
   compile-time definition can now be overridden using commandline options.
   Commandline options are covered in the in the dhcpd.8 man page.

   If you do change any 'Makefile.in' files, save the originals first, so you'll
   have clean copies available when it comes time to apply the next patch.


7. Run './configure' to figure out your system's configuration and generate new
   'Makefile' files from the 'Makefile.in' files.


8. If you had previously customized any 'Makefile' files (as opposed to any
   'Makefile.in' files), now's the time to re-apply your customizations. if
   necessary. (You *did* make a record of them, right?)

   Most of the definitions that used to be in 'Makefile' files have moved to
   defaults.h, so you may not need to make any changes to 'Makefile' files at
   this time.

   Before re-apply any of your old customizations, first check to see if you can
   now accomplish what you need with a commandline option instead of a
   compile-time definition; most defaults and features that once required a
   compile-time definition can now be overridden using commandline options.
   Commandline options are covered in the dhcpd.8 man page.


9. Examine the 'defaults.h' file and customize it if necessary. This file now
   contains many of the definitions that previously lived in Makefile.in.

   Avoid changing items that can also be set using a commandline option.

   If you do change the 'defaults.h file, save the original first, so you'll
   have a clean copy available when it comes time to apply the next patch.


10. Run 'make' to compile the program. If you receive any compile-time errors,
    review the INSTALL document for tips.


11. Kill any running dhcpd, then install the new dhcpd executable. (It often
    lives in /etc/dhcpd or /usr/local/etc/dhcpd, but you may install it
    elsewhere.) You'll probably want to back up your old dhcpd executable before
    installing the new one.

12. Optionally install the new dhcpd.8, bootptab.5, dhcpd.conf.5, and 
    dhcp-bindings-tool.8 man pages manually.


13. Optionally update any startup script you may use to take advantage of new
    commandline options added in this patch.


14. Optionally update your bootptab file to take advantage of new tags added in
    this patch.


15. Optionally update your dhcpd.conf file to take advantage of new
    configuration features added in this patch.


16. Start the new dhcpd executable.



---------------------------------------------------------------------

BUILDING FROM SCRATCH

You can get the current version of the source from 

      http://www.net.princeton.edu/software/dhcpd/

Then see the INSTALL document for instructions.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I'm presently
compiling and running on:

  Solaris 10 SPARC, with gcc 4.2.4

---------------------------------------------------------------------

WHAT'S CHANGED

Changes since PU patch 10:

---

When we receive a packet with htype=0, treat that as an unknown hardware type.
As with packets that specify other unknown hardware types, we log the packet's hlen, 
chaddr, and IPsrc fields, and don't process the packet further.

Added new -H option.  This instructs the server to ignore a DHCP
request when the request contains a "DHCP Client Identifier"
option and its value does not match the htype and chaddr values in the request.
This option may not be specified if the -I option is also specified, as
-I causes the server to ignore the "DHCP Client Identifier" option.
If your intent is that the server identify DHCP clients htype and
chaddr rather than by "DHCP Client Identifier," then you should specify the
-H option.  Omitting it would cause the server to view all the requests
from one device that uses a constant (htype, chaddr) but unique
DHCP Client Identifiers"as the same client, while the device would view
the server's responses as being intended for the multiple
"DHCP Client Identifiers".

The existing message 
  "Client ID option (%s) doesn't correspond to chaddr (%s), (IPsrc=%s)" 
was changed to
  "Client ID option (%s) doesn't correspond to htype/chaddr (%s), (IPsrc=%s)" 
and was demoted from LOG_WARNING to LOG_INFO.

The existing message
   dynamic pool %s has no %d addresses
which is normally logged (at LOG_INFO) only when debuglevel > 3
will be logged (at LOG_NOTICE) regardless of debuglevel when 0 addresses are available.

---

Changed behavior:

When we have an unexpired DHCP lease for a client,
and we receive a DHCPDISCOVER from that client, and we decide to OFFER
the same IP address from the unexpired lease to the client, we
converted the unexpired lease to an OFFER.
If the client SELECTED the offer before the offer expires, the offer
becomes a new lease.

None of that has changed.

In the past, if the client did NOT select the offer before the offer
expires (and nothing else happens to cause that offer to be discarded), 
the expiration of the offer also terminated the old lease
that had existed prior to the offer.

What has changed is that instead, if the offer expires without
having been selected, we now restore the old lease
that had existed prior to the offer.

This is to help reduce the impact of certain clients that obtain a lease,
enter INIT before the lease expires, receive an OFFER from us, ignore
the offer, and then resume using the old lease.  (Apple Mac OS X 10.4.x
began doing that.  It became worse in Apple Mac OS X 10.5.x, 
in iPod OS, and in iPhone OS; each of those systems appear to maintain a cache
of multiple unexpired leases, and may choose to resume using any of them.)

The new behavior helps prevent the DHCP server from handing the unexpired
lease to another client (given that the first client may resume using that
unexpired lease).  It also means that the server may consume many more
IP addresses that it previously did, since it doesn't terminate
leases as promptly as it used to.

Bindings dump file have been modified to take this into account.
If a binding is for a DHCP lease that was unexpired, coverted to an offer,
but not (yet) accepted by the client, the expriration time shown in the
"Summary of Current Bindings" section of the dump file displays the
expiration time of the unexpired lease, not that of the offer.
For a lease in that state, the "Detailed Dump of each Current Binding"
continues to show an "expires_time_t" and
"expires" fields containing the binding's expiration time
(which is the offer's expiration time).  But the detailed dump also
will show an "expire_prior_to_offer_time_t" and "expire_prior_to_offer"
fields containing the unexpired lease's expiration time. 


You can get the old behavior back by specifying the -T commandline option.
That enables the "Offer Terminates Unexpired Lease" feature.

---

The bindings dump file has been modified to add the line
	# offerred_but_not_yet_accepted_by_client=1
to each detailed binding dump if the binding has that flag set.
That flag indicates the binding represents a DHCP offer that
was sent to the client, and the client has not yet accepted the
offer.  

Note that it is possible the binding represents
an unexpired lease that was converted to an offer
and the client has not yet accepted the offer.
Such bindings can be distinguished by the fact that they
have both the offerred_but_not_yet_accepted_by_client=1
line and an expires_prior_to_offer_time_t or an expires_prior_to_offer.
Bindings that are simply offers that don't represent
converted unexpired leases have offerred_but_not_yet_accepted_by_client=1
but do not have an expires_prior_to_offer_time_t or an expires_prior_to_offer.

---

When we send a DHCP Client FQDN Option (option 81), we used to set the
each of the RCODE1 and RCODE2 fields (within this option) to 0, as per 
draft-ief-dhc-dhcp-dns-10.txt.
We now set those each of those two fields to 255, as per RFC4702.

---

At program launch time, we were failing check the bindings against
the bootptab to see which bindings should be deleted due to (some)
consistency checks against bootptab.  Although we performed those checks
each time we re-read the bootptab after launch time, we didn't do it 
the first time we read bootptab at launch time.  Fixed.

Messages explaining that we are deleting a binding due to a change in the bootptab are 
now logged at debug level 3 instead of 4.  These messages were also reworded.

---

The new 'networkalso' statement may be used in the dhcpd.conf file
to declare additional IP network ranges that should be treated as
part of a pool declared in an earlier 'network' statement.
The networkalso statement may be used repeatedly for a given pool.

This allows you to declare a pool of dynamic IP addresses consisting
of a number of non-contiguous ranges.

All of the additional ranges specified in the networkalso statements
for a given pool inherit the same accessflags and relayagents
as the original network statement.  Indeed, the networkalso statement
is simply syntactic sugar used to extend the network statement
without breaking the syntax of the network statement.

There should be no overlap among the IP ranges
specified in all the network and networkalso statements
throughout the dhcpd.conf file.

For details, see the networkalso statement in dhcpd.conf(5).

---

The "Client Steering Feature" is new.  It is disabled by default.

From dhcpd(8):

CLIENT STEERING FEATURE
     The Client Steering feature is a crude form of load  balanc-
     ing.   You  may  use  it when you have multiple servers, and
     wish each client to be steered so the client tends to prefer
     the servers in a particular order.

     The  Client  Steering  feature  may  be  enabled  with   the
     client_steering_enable  statement in the dhcpd.conf(5) file.
     The arguments to that statement are one or more of the  fol-
     lowing   tokens:   client_steering_enable_bootpreply_static,
     client_steering_enable_bootpreply_dynamic,
     client_steering_enable_dhcpoffer_static,                 and
     client_steering_enable_dhcpoffer_dynamic.     Each     token
     enables  the Client Steering feature for just those response
     packets    sent    by    the    server.     For     example,
     client_steering_enable_dhcpoffer_dynamic specifies DHCPOFFER
     packets for dynamic IP addresses.  Client  Steering  is  not
     available for other kinds of response packets.

     The Client Steering feature relies on the  bootp_secs  field
     in  the  header  of  every  packet  sent  by a BOOTP or DHCP
     client.  The client sets this value to the number of seconds
     that  have  elapsed  since the client started trying to boot
     (but see below for exceptions).

     The server computes a Client Steering Hashcode based on  the
     request's DHCP Client Identifier or bootp_chaddr.  (This may
     be tuned via the  client_steering_hash_source  statement  in
     the dhcpd.conf(5) file.)

     The Client Steering Hashcode is used  to  determine  whether
     this  server  is  that  client's  most preferred server, its
     second-most  preferred  server,  its  third-most   preferred
     server, etc.

     You must cause each server to take a different  position  in
     the   sequence  of  servers;  you  specify  this  using  the
     client_steering_server_myself statement in the dhcpd.conf(5)
     file.   For  example,  if  you  had three servers, you would
     specify the value 1 on the one server, 2 on another  server,
     and  3  on  the remaining server.  (You may specify the same
     value on more than one server if you want  multiple  servers
     to respond to the same clients using the same threshholds.)

     If a client's Client Steering Hashcode is 1,  that  client's
     most-preferred    server    will   be   the   server   who's
     client_steering_server_myself  value  is  1;  that  client's
     second-most  preferred  server  will  be  the  server  who's
     client_steering_server_myself value is 2, and that  client's
     third-most   preferred  server  will  be  the  server  who's
     client_steering_server_myself value is 3.  Similarly, If the
     client's  Client Steering Hashcode is 2, that client's most-
     preferred    server    will    be    the    server     who's
     client_steering_server_myself  value  is  2;  that  client's
     second-most  preferred  server  will  be  the  server  who's
     client_steering_server_myself  value is 3, and that client's
     third-most  preferred  server  will  be  the  server   who's
     client_steering_server_myself value is 1.

     The idea is that if you have n servers, each server will  be
     the  most  preferred server for 1/n clients, the second-most
     preferred server for 1/n clients, etc.   (This  assumes  the
     Client Steering Hashcode values are uniformly distributed.)

     For any particular client, the  most  preferred  server  for
     that  client  responds  to  the  client  when  the request's
     bootp_secs is greater than or equal to some low value, typi-
     cally  0 seconds.  The second-most preferred server for that
     client also  responds  to  the  client  when  the  request's
     bootp_secs  is greater than or equal to some slightly higher
     value, for example, 3  seconds.   The  third-most  preferred
     server  for that client also responds to the client when the
     request's bootp_secs  is  greater  than  or  equal  to  some
     slightly higher value, for example, 6 seconds, and so on.

     You     specify     these     threshholds     using      the
     client_steering_delay_secs  statement  in  the dhcpd.conf(5)
     file.  For example, if you  had  three  servers,  you  might
     specify the values 0, 3, and 6.

     If you specify n values for the  client_steering_delay_secs,
     then  presumably you have n servers, and will specify one of
     the    values    in    the    range    1...n     for     the
     client_steering_server_myself  value on each server, specif-
     ing each value once.  (It is permissible to specify the same
     client_steering_server_myself  value on multiple servers, if
     you want multiple servers to respond to  clients  using  the
     same threshholds.)

     Ideally, a client will transmit  its  first  request  packet
     with  bootp_secs  set  to  0.   That client's most preferred
     server will respond to the client.  If  the  client  doesn't
     receive  a  response  from  that  server, it retransmits its
     request  packet  with  bootp_secs   set   slightly   higher.
     Ideally,  this slightly higher value will be large enough to
     cause both the client's most preferred  server  and  second-
     most  preferred  server  to  respond.  If the client doesn't
     receive a response, it retransmits its request  packet  with
     bootp_secs  set slightly higher.  Ideally, this higher value
     will be large enough to cause the  client's  most  preferred
     server,  second-most  preferred  server, and third-most pre-
     ferred server to respond, and so on.   The  result  is  that
     most of the time, the client would hear only a response from
     that  client's  most  preferred  server,  but  the  multiple
     servers  would still provide a measure of redundancy for the
     client when the most preferred server is unavailable.

     Note that the bootp_secs value specified by some clients  is
     not accurate.  RFC951 gives the client leeway in how it sets
     this field.  And the pattern of timeouts and retransmissions
     used  by  different platforms may vary widely.  As a result,
     it   may   be    difficult    to    select    a    set    of
     client_steering_delay_secs  values  that  work  well  for  a
     variety of clients.  If a client always specifies a very low
     bootp_secs value, only one of the servers may respond to the
     client; the Client Steering  will  force  that  client  rely
     entirely on a single server.  Conversely, if a client always
     specifies a large bootp_secs value, all of the servers  will
     respond  to the client; that client will not be "steered" by
     the Client Steering feature.

     The Client Steering feature may be of particular value  when
     the Offer Terminates Unexpired Lease feature is not enabled.
     If you have multiple servers  each  with  its  own  pool  of
     dynamic  IP addresses, you will find that over time a client
     may obtain a lease on a different dynamic  IP  address  from
     each  server.   Although  the  client may need only a single
     lease, each of the servers will be maintaining a  lease  for
     the  client.   This  wastes  dynamic  IP address pool space.
     Enabling  the  Client  Steering  feature  for   dynamic   IP
     addresses  may  help  reduce  the  waste, as it will tend to
     cause each client to choose leases from that  client's  most
     preferred server, and less often from other servers.


From dhcpd.conf(5):

  client_steering_enable
     The client_steering_enable statement is used to  enable  the
     Client Steering feature.  The format is

          client_steering_enable
          [client_steering_enable_bootpreply_static]
          [client_steering_enable_bootpreply_dynamic]
          [client_steering_enable_dhcpoffer_static]
          [client_steering_enable_dhcpoffer_dynamic]

     One or more arguments may be specified; each of the possible
     arguments  enables  Client Steering for a particular kind of
     response packet sent by the server.

     The client_steering_enable_bootpreply_static argument speci-
     fies  that  Client Steering should be enabled for BOOTPREPLY
     packets   that   contain    static    IP    addresses    The
     client_steering_enable_bootpreply_dynamic argument specifies
     that Client Steering should be enabled for BOOTPREPLY  pack-
     ets    that    contain    dynamic    IP    addresses.    The
     client_steering_enable_dhcpoffer_static  argument  specifies
     that Client Steering should be enabled for DHCPOFFER packets
     that     contain     static     IP      addresses.       The
     client_steering_enable_dhcpoffer_dynamic  argument specifies
     that Client Steering should be enabled for DHCPOFFER packets
     that contain dynamic IP addresses.

     The statement may appear more than once in the file;  if  it
     does, the arguments are concatenated.

     The default behavior is for Client Steering to be disabled.

     If Client Steering is enabled, the configuration  file  must
     also    contain    the   client_steering_server_myself   and
     client_steering_delay_secs statements.

  client_steering_hash_source
     The client_steering_hash_source statement is used to specify
     what data source should be used to compute the Client Steer-
     ing Hashcode.  Its value is unused when Client  Steering  is
     disabled.  The format is:

          client_steering_hash_source [ chaddr | clientid ]

     If chaddr is specified, the  bootp_chaddr  (client  hardware
     address)  field is used.  If clientid is specified, the DHCP
     Client Identifier option value is used.  (If the packet con-
     tains  no explicit DHCP Client Identifier option, the server
     synthesizes a DHCP Client Identifier value by  concatenating
     the  bootp_htype  (hardware  type)  and bootp_chaddr (client
     hardware address) fields.

     If left unspecified, client_steering_hash_source defaults to
     using clientid.

  client_steering_hash_function
     The  client_steering_hash_function  statement  is  used   to
     specify  which  hash  function should be used to compute the
     Client Steering Hashcode.  The format is:


          client_steering_hash_source [ popx31 | lastbyte ]

     If popx31 is specified, the hash is computed using a general
     purpose hash function.

     If lastbyte is specified, the hash is computed based on  the
     last  byte  of  the  input  string, ignoring the rest of the
     input string.  That's faster than the popx31 hash  function.
     It's  only suitable to use when you believe the last byte of
     the input string will be uniformly distributed  relative  to
     the  number  of hash buckets, and the number of hash buckets
     is < 256.  That's typically true if you have decided to  use
     the  client's  chaddr  as  the  client_steering_hash_source.
     It's also typically true if you  have  decided  to  use  the
     clientid  as the client_steering_hash_source if you are also
     requiring  the  DHCP  Client   Identifier   to   match   the
     bootp_htype concatenated with the bootp_chaddr.  But for the
     more  general  case  of  arbitrary  DHCP  Client  Identifier
     values, it is not true, so the lastbyte hash function is not
     appropriate to use in the more general case.

     If left unspecified, client_steering_hash_source default  to
     using popx31.

  client_steering_server_myself
     The  client_steering_server_myself  statement  is  used   to
     assign a server number for this server for use by the Client
     Steering feature.  Its value is unused when Client  Steering
     is disabled.  The format is:

          client_steering_server_myself server_number

     The value specified must  be  an  integer  in  the  range  1
     through    the   number   of   values   specified   in   the
     client_steering_delay_secs statements. In order  to  specify
     this  value,  the  configuration  file  must also specify at
     least one client_steering_delay_secs value.

     The value specified has no  particular  significance.   It's
     simply  used  to determine the position of this server in an
     ordered list of servers.  You assign a  different  value  to
     each  server  to  allow  the Client Steering feature to dif-
     ferentiate each server from the others.

     For  example,  if  you  specified  three   values   in   the
     client_steering_delay_secs      statement,      then     the
     client_steering_server_myself  value  should  be  1  on  one
     server, 2 on another server, and 3 on another server.

     It is permissible to specify  the  same  value  on  multiple
     servers  (to  cause  multiple servers to make the same deci-
     sions with regard to the Client Steering feature).

  client_steering_delay_secs
     The client_steering_delay_secs statement is used to  specify
     the  numbers  of  seconds  that  the Client Steering feature
     should use as thresholds when deciding if it should  respond
     to  a  client.   Its value is unused when Client Steering is
     disabled.  The format is:

          client_steering_delay_secs  seconds1   [   seconds2   [
          seconds3 ]... ]

     One or more whitespace-separated values  may  be  specified;
     each  value  is an integral number of seconds in the range 0
     through 2^16-1.  The statement may appear more than once; if
     it  does,  the  values  are concatendated as if they had all
     appeared in a single statement.


     These values are only used when the Client Steering  feature
     is  enabled  for the particular request packet the server is
     considering.

     Based upon the  value  client_steering_server_myself  and  a
     client_steering_hashcode  computed  based  on  the  client's
     chaddr or DHCP Client Identifier, the server  determines  if
     it  this client's "most preferred" server, "second-most pre-
     ferred server", "third-most preferred server", etc.

     If the server is this client's "most preferred"  server,  it
     will suppress any reply if the request's bootp_secs field is
     less  than  seconds1.   If  the  server  is  this   client's
     "second-most  preferred"  server, it will suppress any reply
     if the request's bootp_secs field is less than seconds2.  If
     the  server  is this client's "third-most preferred" server,
     it will suppress any reply if the request's bootp_secs field
     is less than seconds3, and so on.

     The first value typically will be  0.   You  would  normally
     specify the same set of values on all your servers.

     For example, if you have three servers,  you  might  specify
     the values: 0, 3, 6.

---

Upgraded from autoconf 2.63 to 2.65.

Replaced install-sh with install.sh version 2009-04-28.21 from automake 1.11.1
Replaced config.guess with config.guess version 2009-11-20 new version from automake 1.11.1.
Replaced config.sub with config.sub version 2009-11-20 from automake 1.11.1.
Replaced missing with missing version 2009-04-28.21 from automake 1.11.1.


=========================================================================

Princeton patch 10
October 24 2008

UPDATING FROM PATCHLEVEL 9

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patches 1, 2, 3, 4, 5, 6, 7, 8, and 9 already applied.

Assuming you have already applied the previous patches, you can apply
this patch as follows:

0. Since this patch introduces new behavior as well as bug fixes, review the
   "WHAT'S CHANGED" section below before proceeding.


1. Make a record of any local customizations you have made to the product, such
   as changes you have made to 'Makefile' (or possibly 'Makefile.in') and
   'defaults.h'. If you did customize either 'Makefile.in' or 'defaults.h'
   files, put the original version back to ensure the patch will apply cleanly.


2. Change to the directory containing the dhcpd source, and feed the patch file
   to the 'patch' program. (The 'patch' program is not supplied here; it is
   included with many operating systems, and is freely available from many
   software libraries.) E.g. using GNU patch: 

   patch -p0 < CMU-dhcpd-3.3.7-PU-patch10

3. Please check for, and remove, any of the following obsolete files you find 
   ('patch' may have removed them for you):

   ./configure.in
   ./install.sh


4. Fix permissions that 'patch' was unable to do:

   chmod +x tools/dhcp-bindings-tool


5. Run 'make distclean' to remove old object files, Makefiles and
   configuration info.


6. If you had previously customized any 'Makefile.in' files (as opposed to
   customizing any 'Makefile' files) , now's the time to re-apply your
   customizations if necessary. (You *did* make a record of them, right?)

   Most of the definitions that used to be in Makefile.in have moved to 
   defaults.h, so you may not need to make any changes to any 'Makefile.in' 
   files at this time.

   Before re-apply any of your old customizations, first check to see if you can
   now accomplish what you need with a commandline option instead of a
   compile-time definition; most defaults and features that once required a
   compile-time definition can now be overridden using commandline options.
   Commandline options are covered in the in the dhcpd.8 man page.

   If you do change any 'Makefile.in' files, save the originals first, so you'll
   have clean copies available when it comes time to apply the next patch.


7. Run './configure' to figure out your system's configuration and generate new
   'Makefile' files from the 'Makefile.in' files.


8. If you had previously customized any 'Makefile' files (as opposed to any
   'Makefile.in' files), now's the time to re-apply your customizations. if
   necessary. (You *did* make a record of them, right?)

   Most of the definitions that used to be in 'Makefile' files have moved to
   defaults.h, so you may not need to make any changes to 'Makefile' files at
   this time.

   Before re-apply any of your old customizations, first check to see if you can
   now accomplish what you need with a commandline option instead of a
   compile-time definition; most defaults and features that once required a
   compile-time definition can now be overridden using commandline options.
   Commandline options are covered in the dhcpd.8 man page.


9. Examine the 'defaults.h' file and customize it if necessary. This file now
   contains many of the definitions that previously lived in Makefile.in.

   Avoid changing items that can also be set using a commandline option.

   If you do change the 'defaults.h file, save the original first, so you'll
   have a clean copy available when it comes time to apply the next patch.


10. Run 'make' to compile the program. If you receive any compile-time errors,
    review the INSTALL document for tips.


11. Kill any running dhcpd, then install the new dhcpd executable. (It often
    lives in /etc/dhcpd or /usr/local/etc/dhcpd, but you may install it
    elsewhere.) You'll probably want to back up your old dhcpd executable before
    installing the new one.

12. Optionally install the new dhcpd.8, bootptab.5, dhcpd.conf.5, and 
    dhcp-bindings-tool.8 man pages manually.


13. Optionally update any startup script you may use to take advantage of new
    commandline options added in this patch.


14. Optionally update your bootptab file to take advantage of new tags added in
    this patch.


15. Optionally update your dhcpd.conf file to take advantage of new
    configuration features added in this patch.


16. Start the new dhcpd executable.



---------------------------------------------------------------------

BUILDING FROM SCRATCH

You can get the current version of the source from 

      http://www.net.princeton.edu/software/dhcpd/

Then see the INSTALL document for instructions.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I'm presently
compiling and running on:

  Solaris 9  SPARC, with gcc 4.1.2
  Solaris 10 SPARC, with gcc 4.2.4

---------------------------------------------------------------------

WHAT'S CHANGED

Changes since PU patch 9:

---

You may dump the packet statistics to a file by sending a SIGWINCH to dhcpd.
(This signal is not available on all platforms.)  

These are the same packet statistics included at the start of a bindings dump,
but performing just a statistics dump doesn't involve the overhead of performing 
a complete bindings dump. The statistics dumped with SIGWINCH are also surrounded 
with a start and stop delimiter line containing the time_t value, which may be helpful 
if you are parsing this data.

The statistics file defaults to /tmp/dhcpd.statistics, and may be overridden
with the new commandline argument -s.

(The bindings dump output has not changed.)

---

Added new dhcpd.conf optional statements: delay_reply_dhcpoffer, 
delay_reply_dhcpack, delay_reply_dhcpnak, delay_reply_bootpreply, and
delay_reply_default.

Here is the new information from the dhcpd.conf man page:

     These statements are optional, and may be used to cause  the
     server  to add a delay before sending BOOTPREPLY, DHCPOFFER,
     DHCPACK, and DHCPNAK packets.

     Specify:

          delay_reply_dhcpoffer n
          delay_reply_dhcpack n
          delay_reply_dhcpnak n
          delay_reply_bootpreply n
          delay_reply_default n

     where n is an integer (n < 2^32-1) specifying the number  of
     microseconds   (millionths  of  a  second)  to  delay.   The
     delay_reply_default value is used when a no  value  specific
     to  the  flavor  of  packet  has been specified.  All values
     default to 0.

---

When we re-read the bootptab file because it has changed, we 
previously invalidated a current DHCP lease in the following
situations:

   * the leased IP address is no longer in bootptab

   * the leased IP address was static, and the IP address in bootptab
     now has a different hardware address or Client Identifier associated
     with it

We have added the following two cases that will also invalidate
the current DHCP lease:

   * the leased IP address was static, and the hardware type (htype)
     for the lease does not match the hardware type for the
     IP address in bootptab

   * the leased IP address was static, but the hostname for the lease
     does not match the hostname for the IP address in bootptab

---

If we receive a DHCPRELEASE message for a "lease" that represents
an offer we made which the client never accepted, ignore the DHCPRELEASE.

This is to work around a bug introduced by Microsoft in multiple versions
of Windows shortly before August 2003.

The bug is that sometimes the DHCP client sends a DHCPDISCOVER,
receives DHCPOFFER(s), then sends a DHCPRELEASE for its previous
DHCP lease, then sends a DHCPREQUEST for (one of) the offered lease(s).

If the IP address that was part of the previous lease is the same
one as the one that was offerered and then requested, we have
a problem.  Our server implements an offer as a very short lease (not
as some unique structure different than a lease).
As a result, the DHCPRELEASE causes the offer to be discarded.
When the DHCPREQUEST arrives, we no longer have an outstanding offer
for this client.

This is a client bug; when it sent the DHCPDISCOVER, it must have moved
to the INIT state.  As a result, it no longer is BOUND, so is not
entitled to send a DHCPRELEASE.  Furthermore, at the time it
sends the DHCPRELEASE it is in the SELECTING state (it has received
the DHCPOFFER and has not yet sent the DHCPREQUEST); DHCPRELEASE
is not a message a client may sent in the SELECTING state.

We refer to this as the "Microsoft Windows DHCP RELEASE while SELECTING bug."

We reported the bug to Microsoft.  They agreed that this behavior is
a new one in Windows, added to implement a new feature.
However, they do not agree that it is a bug; their response is that
a single DHCP client instance (i.e. one operating on a single interface
with a single Client Identifier) is permitted to be both in the 
BOUND and SELECTING state simultaneously.    (This implies that
one such instance may have two simultaneous DHCP leases.)
Since the client BOUND, it may send a DHCPRELEASE, and since the client
is also SELECTING, it may send a DHCPREQUEST.
I tried to convince them that this is not permitted by 
RFC 1541, but their response was that since the RFC did not forbid
a client from being in two states at once, it is permitted.
This seems incorrect to me; a finite state automata can be in only
one state at a time.  Nevertheless, Microsoft said that their behavior
is correct; they will not change it.

As a workaround, when we send a DHCPOFFER, we mark the coresponding
"lease" in memory to reflect that it represents an offer that the client
has not yet accepted.  If the client later sends a DHCPREQUEST for this
offer, we clear that mark.  This mark allows us to determine if a lease
structure in memory is a true lease, or simply an unclaimed offer.

When we receive a DHCPRELEASE, if the lease referred to is one marked
in this way, we ignore the DHCPRELEASE.  From our point of view, the
client is trying to release something isn't a true lease.  As far
as we're concerned, the client is in SELECTING state, so cannot
release.

---

Added new '-E so_rcvbuf' option to let you override the operating
system's default size for the socket receive buffer.

---

Added new '-F' option to let you enable the new "Don't Look for Default
Bootfile" feature.

When no bootfile is specified in the client's request and the bootptab, the
server normally looks for a local bootfile using a default filename.  If you
do not store bootfiles locally (or do not store any using the default
filenames) checking for these files is wasted effort.  Enable the "Don't Look
for Default Bootfile" feature to cause the server to not look for a local
bootfile with a default filename when no bootfile is specified in the
client's request and the bootptab.

---

Added new 'readtabinterval' optional keyword to dhcpd.conf.

The readtabinterval statement is optional, and may be used to reduce the
frequency at which dhcpd(8) checks the bootptab(5) file for changes.

If readtabinterval is unspecified (or specified as 0), then before processing
each received packet, the server checks the bootptab(5) file's modification
time. If the file's modification time is newer than the file's modification time
at the time the file was last read, the server re-reads the bootptab(5) file.

If a positive value is specified, then before processing each received packet,
the server checks whether the speci- fied number of seconds have passed since
the bootptab(5) file was last read. If fewer seconds have passed, the server
does not check file's modification time; the file is not re-read. If the
specified number of seconds have passed, the server proceeds to examine the
bootptab(5) file's modification time (as described earlier).

This feature allows you to reduce the frequency of the (relatively) expensive
retrieval of the bootptab(5) file's modification time.

The bootptab(5) is still re-read when the server is signalled to do so,
regardless of the use of readtabinterval.

---

Added new 'readconfinterval' optional keyword to dhcpd.conf.

The readconfinterval statement is optional, and may be used to reduce the
frequency at which dhcpd(8) checks the dhcpd.conf(5) file for changes.

If readconfinterval unspecified (or specified as 0), then before processing each
received packet, the server checks the dhcpd.conf(5) file's modification time.
If the file's modification time is newer than the file's modification time at
the time the file was last read, the server re-reads the dhcpd.conf(5) file.

If a positive value is specified, then before processing each received packet,
the server checks whether the speci- fied number of seconds have passed since
the dhcpd.conf(5) file was last read. If fewer seconds have passed, the server
does not check file's modification time; the file is not re-read. If the
specified number of seconds have passed, the server proceeds to examine the
dhcpd.conf(5) file's modification time (as described earlier).

This feature allows you to reduce the frequency of the (relatively) expensive
retrieval of the dhcpd.conf(5) file's modification time.

The dhcpd.conf(5) is still re-read when the server is signalled to do so,
regardless of the use of readconfinterval. It is also re-read whenever the
server re-reads the bootptab(5) file.

---

The format of a message produced when a DHCP packet's hlen field
does not correspond with its htype field has changed.

The old message looked like this:

  bad addr len from DHCP client with Ethernet address 00:01:D0:AF:B0:02 (IPsrc=192.168.1.3)

The new message looks like this:

  bad addr len (BOOTP htype=1, but hlen=28) from DHCP client with Ethernet address 00:01:D0:AF:B0:02 (IPsrc=192.168.1.3)

---

Added a new tool 'dhcp-bindings-tool' which may be used to manipulate the
bindings directory.

From the dhcp-bindings-tool(8) man page:

    dhcp-bindings-tool  may be used to read a bindings directory
	in the format used by Carnegie Mellon University dhcpd  with
	the  Princeton University patches, henceforth referred to as
	CMU+PU dhcpd, or simply dhcpd.

	After reading the bindings into memory, the program may  op-
	tionally prune the in-memory data.  After any optional prun-
	ing, the resulting in-memory data may be written to create a
	new bindings directory, written to a plain text report file,
	and/or used as the basis to write a  plain  text  statistics
	file.

	The program can also read the plain text report file instead
	of a bindings directory.  This allows you to use the program
	to  write a report based on a bindings directory, manipulate
	that report using other software, then  read  the  resulting
	report to create a new bindings directory.

	The program relies on perl 5.8.0 or later, and the following
	modules from the Comprehensive Perl Archive Network  (CPAN):
	Readonly, Statistics::Descriptive.

From the INSTALL file:

   Optionally copy tools/dhcp-bindings-tool to wherever is appropriate on your
   system for local utilities (e.g. perhaps /usr/local/bin).

   This tool is not necessary to use dhcpd; it is a utility to allow you to
   manipulate the bindings directory created by dhcpd.

   The tool requires perl version 5.8.0 or later.  If your perl is not in
   /usr/local/bin, you may need to edit the tool's first line to specify
   your perl location.

   The tool requires CPAN modules Readonly and Statistics::Descriptive.

---

Added two alternate hash functions, neither of which is used by default.

In INSTALL and defaults.h, recommended that you increase
HASHTABLESIZE to a much larger number than the default (257),
and uncomment ALT_HASHFN_2.

These changes are best done at initial installation.  While either
(or both) may be done later, if you do either (or bother) you will need to stop the 
server and erase the entire contents of the bindings directory.   Discarding all 
bindings is disruptive to clients.

---

Fix AC_UNP_CHECK_TYPE in aclocal.m4 so it works in gcc 4.1.2.
The bug would cause configure to believe that the system lacked a definition for socklen_t,
causing us to provide our our definition, which could lead to duplicate or conflicting
definitions.

---

Remove declaration of interface_tab[] from bootpd.h.
This was dead code, and also caused a compile-time error in gcc 4.1.2.

---

#include <strings.h> if present.
This will eliminate some warnings (e.g. for bcopy(), bcmp(), and bzero()) on some systems.

---

Upgraded from autoconf 2.13 to 2.63.

Renamed configure.in to configure.ac.

Deleted acconfig.h.

Replaced install-sh with install.sh version 2008-01-08 from automake 1.10.1.
Replaced config.guess with config.guess version 2008-01-16 new version from automake 1.10.1.
Replaced config.sub with config.sub version 2006-12-25.00 from automake 1.10.1.
Add missing version 2006-05-10.23 from automake 1.10.1.

---

=========================================================================

Princeton patch 9
May 15, 2002

UPDATING FROM PATCHLEVEL 8

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patches 1, 2, 3, 4, 5, 6, 7, and 8 already applied.

Assuming you have already applied the previous patches, you can apply
this patch as follows:

0. Since this patch introduces new behavior as well as bug fixes, review the
   "WHAT'S CHANGED" section below before proceeding.


1. Make a record of any local customizations you have made to the product, such
   as changes you have made to 'Makefile' (or possibly 'Makefile.in') and
   'defaults.h'. If you did customize either 'Makefile.in' or 'defaults.h'
   files, put the original version back to ensure the patch will apply cleanly.


2. Change to the directory containing the dhcpd source, and feed the patch file
   to the 'patch' program. (The 'patch' program is not supplied here; it is
   included with many operating systems, and is freely available from many
   software libraries.) E.g. using GNU patch: 

   patch -p0 < CMU-dhcpd-3.3.7-PU-patch9


3. Run 'make distclean' to remove old object files, Makefiles and
   configuration info.


4. If you had previously customized any 'Makefile.in' files (as opposed to
   customizing any 'Makefile' files) , now's the time to re-apply your
   customizations if necessary. (You *did* make a record of them, right?)

   Most of the definitions that used to be in Makefile.in have moved to 
   defaults.h, so you may not need to make any changes to any 'Makefile.in' 
   files at this time.

   Before re-apply any of your old customizations, first check to see if you can
   now accomplish what you need with a commandline option instead of a
   compile-time definition; most defaults and features that once required a
   compile-time definition can now be overridden using commandline options.
   Commandline options are covered in the in the dhcpd.8 man page.

   If you do change any 'Makefile.in' files, save the originals first, so you'll
   have clean copies available when it comes time to apply the next patch.


5. Run './configure' to figure out your system's configuration and generate new
   'Makefile' files from the 'Makefile.in' files.


6. If you had previously customized any 'Makefile' files (as opposed to any
   'Makefile.in' files), now's the time to re-apply your customizations. if
   necessary. (You *did* make a record of them, right?)

   Most of the definitions that used to be in 'Makefile' files have moved to
   defaults.h, so you may not need to make any changes to 'Makefile' files at
   this time.

   Before re-apply any of your old customizations, first check to see if you can
   now accomplish what you need with a commandline option instead of a
   compile-time definition; most defaults and features that once required a
   compile-time definition can now be overridden using commandline options.
   Commandline options are covered in the dhcpd.8 man page.


7. Examine the 'defaults.h' file and customize it if necessary. This file now
   contains many of the definitions that previously lived in Makefile.in.

   Avoid changing items that can also be set using a commandline option.

   If you do change the 'defaults.h file, save the original first, so you'll
   have a clean copy available when it comes time to apply the next patch.


8. Run 'make' to compile the program. If you receive any compile-time errors,
   review the INSTALL document for tips.


9. Kill any running dhcpd, then install the new dhcpd executable. (It often
   lives in /etc/dhcpd or /usr/local/etc/dhcpd, but you may install it
   elsewhere.) You'll probably want to back up your old dhcpd executable before
   installing the new one.


10. Optionally update any startup script you may use to take advantage of new
    commandline options added in this patch.


11. Optionally update your bootptab file to take advantage of new tags added in
    this patch.


12. Optionally update your dhcpd.conf file to take advantage of new
    configuration features added in this patch.


13. Start the new dhcpd executable.


14. Optionally install the new dhcpd.8, bootptab.5, and dhcpd.conf.5 man
    pages manually.


---------------------------------------------------------------------

BUILDING FROM SCRATCH

You can get the current version of the source from 

      http://www.net.princeton.edu/software/dhcpd/

Then see the INSTALL document for instructions.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I'm presently
compiling and running on Solaris 8 SPARC systems, compiling with
gcc 3.0.4.

---------------------------------------------------------------------

WHAT'S CHANGED

Changes since PU patch 8:

---

Updated README and dhcpd.8 to reflect that the product's home is now:
  http://www.net.princeton.edu/software/dhcpd/

---

Corrected INSTALL doc; it suggested you block the bootp server port at your
firewall router, but said the port port number was 161.  The bootp server
port is 67.

---

Changed behavior in processing DHCPDECLINE messages.  

RFC2131 says that the message MUST contain a Server Identifier option, but does
not specify how the server should process/verify this field (e.g. should we
ignore the message if the field is missing or specifies a Server Identifier
other than ourself?).

Previously we ignored the field. Now we examine the field; if it is present and
not equal to my_ip_addr, we ignore the message. If it is not present at all, we
continue to process the message (as before).

Some DHCP clients (Win98??) mistakenly set the Server Identifier option to 
255.255.255.255 in DHCPDECLINE messages.  To continue to accomodate these,
when we see this Server Identifier, we *will* process the message as before.

---

Added the optional 'known_server_identifier' keyword to the dhcpd.conf file.
You may use this to ask the server to log each time it encounters a client
that specifies a Server Identifier Option value for an unknown DHCP server.
This may help alert you to rogue DHCP servers.

Here is the description from the dhcpd.conf man page:

  known_server_identifier
     The known_server_identifier statement is optionally used  to
     describe each DHCP Server on the network.  The format is:

          known_server_identifier ipaddress

     Specify the ipaddress of a DHCP  server  operating  on  your
     internetwork.   If  there are multiple DHCP servers, specify
     each in a separate statement.

     This statement is optional;  if  present,  the  server  will
     attempt  to  log each time a client specifies a Server Iden-
     tifier Option containing a value that is neither  my_ip_addr
     nor  one  of  those  specified as a known_server_identifier.
     This may help alert you to rogue DHCP servers.

     The server checks for a Server Identifier Option in  DHCPRE-
     QUEST  messages  (when  a  client is SELECTING), DHCPRELEASE
     messages, and DHCPDECLINE messages.  When the  Server  Iden-
     tifier  Option is specified in one of these messages, but is
     not equal to my_ip_addr, the server checks  to  see  if  you
     have  specified  any known_server_identifier values.  If so,
     it checks to see if the Server Identifier Option matches one
     of  those; if it matches none of them, the server logs it as
     an "unknown Server Identifier."

     Since    the     server     does     not     examine     the
     known_server_identifier  values  when  the Server Identifier
     Option matches my_ip_addr, you need not list  your  server's
     own IP address as a known_server_identifier.

     The known_server_identifier statement is  optional;  if  you
     have  none,  the server skips the check; it will not log any
     "unknown Server Identifier."

     This check is only used to provide you with some  hint  that
     there  may  be rogue DHCP servers operating on your network.
     It is possible for rogue DHCP servers  to  operate  on  your
     network and not be noticed by this check.

     Note the statement does not allow you to declare  a  set  of
     Server  Identifier  Option  values that the server will con-
     sider equivalent to itself.

---

Relocated configuration code that determines if ioctls on sockets should use
STREAMS ioctls instead of SIOCxxx ioctls. It used to be in configure.in; it's
now in a new macro IST_SYS_SOCKET_IOCTLS_USE_STREAMS in aclocal.4. The
preprocessor symbol defined has changed from USE_STREAM_IOCTLS to
SYS_SOCKET_IOCTLS_USE_STREAMS.

---

An error message we may produce implied that the error is within the DHCP server
(inconsistent hash tables) while in fact the error may be caused by the client.

Producing the message requires a specific combination of circumstances. The
client (cliid) must have an existing DHCP lease. The client must then send a
DHCPREQUEST asking to RENEW a lease, but specify a 'ciaddr' field (which is the
IP address of the lease the client is asked to renew) which is *not* the
client's current leased address. Moreover, this incorrect ciaddr must be an IP
address listed in the server's bootptab as a dynamically-assigned IP address,
not presently bound to any client, and also be one that this cliid *could* be
awarded based upon access policy (if it made the appropriate request from the
appropriate subnet).

In that circumstance, the message we produced was:

  dhcp_request(): RENEWING/REBINDING/BOUND: did *NOT* find client's IP (192.168.2.2) in ipboundhshtbl,...
  but did find entry for this cliid (01 01 02 03 04 05 06 ) in boundhshtbl, assigned IP address 192.168.1.1!
  freeing binding

It's been reworded to say:

  dhcp_request(): RENEWING/REBINDING/BOUND: did *NOT* find client's claimed IP (ciaddr=192.168.2.2) in ipboundhshtbl,...
  but did find entry for the cliid (01 01 02 03 04 05 06 ) in boundhshtbl, assigned IP address 192.168.1.1!...
  I.e. the client is trying to renew a lease on an IP address (192.168.2.2) that is not leased to it.
  freeing binding

Note that we still take the same action as before; we discard the client's
current binding, on the assumption that the client is very confused, and
apparently no longer thinks it is bound to the IP address we think the client
is bound to.

Whether or not this message should still be logged as an "error" (since it may be just a confused client,
not a server bug) is an open question.

---

Sometimes a broken DHCP client will obtain a lease on a dynamic IP address,
allow the lease to expire, then resume using the IP address well after the
expiration. Sometimes the broken client sends DHCPREQUEST packets attempting to
renew the lease, acting like it is in RENEWING or REBINDING state.

Previously, if the DHCP server could tell the specified IP address is
topologically inappropriate for the client (based on giaddr), the server would
NAK the client. If the DHCP server could tell the specified IP address was
inappropriate for the client based on access policy set for the dynamic address
pool, the server would NAK the client. If the DHCP server had a current lease
for the IP address, but for a different Client Identifier, the server would NAK
the client. Otherwise if the IP address was not in the bootptab, or the IP
address in the bootptab was marked dynamic but not a member of any dynamic pool
this DHCP server handles, the server ignored the client.

All that remains the same, but the following has changed:

If the specified IP address is in the server's bootptab, is marked dynamic, is a
member of a dynamic pool this server handles, and this server has no current
lease for this IP address, the server will now NAK the client instead of
ignoring it.

This is because the server knows the client is wrong. (The server is
authoritative for this IP address and knows there is no lease for it, so the
client trying to renew a lease on this IP address must be wrong. The client
could never successfully renew an unbound dynamic address from this server, and
even if the client is REBINDING, no other DHCP server will renew that particular
IP address, since it's THIS server that's authoritative for that IP address.)

We NAK the client in the hope it will send it back to INIT state (although the
client may be so broken that it may ignore us entirely).

When it does this, it logs messages like the following at LOG_INFO when
debuglevel > 2:

   client 01 01 02 03 04 05 06 in RENEWING/REBINDING/BOUND state tried to renew dynamic IP address 192.168.1.2 ...
   but this IP address is not presently bound and is a member of one of my pools, so we will NAK the client

---

If a DHCP packet received from a client failed to terminate its options with an
"END" option, we treated this as an error, logging a message like the following,
and ignoring the packet:

   error parsing DHCP packet, ignoring DHCP client (chaddr=01 01 02 03 04 05 06 ,  but may be inaccurate), (IPsrc=192.168.4.5)

The spec does not require the options sent by the client to always terminate
with an "END" option; if no "DHPC Options Overload" option is present, leaving
off the "END" option simply means the options continue through the end of the
relevant field in the packet.

We no longer complain when the "END" option is not present, and we no longer
ignore the packet.

---

A malformed DHCP packet received from a client might cause the server to loop.
Specifically, if the packet's "Options" field contained a DHCP Overload Option
that specified that the "file" field is overloaded, and the "file" field
contained another DHCP Overload Option that specified that the "file" field is
overloaded, we could loop processing the "file" field. A similar problem could
happen with the "sname" field.

We will no longer try to process an overloaded field (file, sname) more
than once.

---

A malformed DHCP packet received from a client might cause the server to try to
parse data from memory as "option" data. Specifically, if the packet's "Options"
field contained an option that contained a "length" byte indicating the option
extended beyond the end of the "Options" field (or the option began on the final
byte of the field), we could attempt to read bytes in memory that followed that
field as if they were option values. Results could be unpredictable.

The same problem affected parsing of overloaded file and sname fields.

Now we report that the "DHCP options overflowed available space in packet", and
discard the malformed packet.

---

Fix typo in log message:
  dchp_request(): no current lease or offer for SELECTING client, sending NAK (cliid=01 00 01 02 03 04 05)
  ^^^^

now reads:
  dhcp_request(): no current lease or offer for SELECTING client, sending NAK (cliid=01 00 01 02 03 04 05)

---

Added a "Lone DHCP Server" feature, suggested by Mike Weller
<weller at gordon dot chem dot wayne dot edu>.

Here is the relevant section of the man page:

   Specifying the -L commandline option enables the Lone DHCP 
   Server feature.  The feature causes the server to behave in
   ways that may be helpful, but would normally  be  unsafe  in
   the presence of other DHCP servers.

     RENEWING versus REBINDING

     When we receive a DHCPREQUEST  from  a  client,  it  is  not
     always  possible  for  us  to  distinguish  the client state
     RENEWING from REBINDING. (This is  because  in  some  situa-
     tions, we must see the IP destination address of the DHCPRE-
     QUEST packet to distinguish the two cases. The  IP  destina-
     tion  address  is  not  available  to an application using a
     datagram socket  in  many  BSD-derived  sockets  implementa-
     tions.)

     This often does not create any  difficulty,  however,  there
     are times we wish to respond to a client differently depend-
     ing on whether the client is in the RENEWING or the  REBIND-
     ING  state.  When a client asks us to renew a lease which we
     have not granted the client, we want to send a DHCPNAK. How-
     ever,  if  the  client  is  REBINDING,  the  client may have
     received the lease from another DHCP  server,  and  in  that
     case,  we  must  be  silent.   That's because we do not know
     definitively  that  the  client  may  not  be  granted   the
     requested lease, as another DHCP server may be able to grant
     the client's request.

     Our  implementation  normally   follows   the   conservative
     approach  in the situations above: it assumes the client may
     be REBINDING, so we are silent. The result is that REBINDING
     clients  will  work properly, but RENEWING clients that we'd
     like to NAK may be allowed to keep using  their  old  leases
     (until  the  client  believes  the lease has expired, or the
     client reboots).

     This is the only safe way we can run if there are other DHCP
     servers on the network.

     If you enable the Lone DHCP Server feature, instead of  fol-
     lowing  the  conservative approach above, we will assume the
     client is in the RENEWING state, so we will send a DHCPNAK.

     Sending a DHCPNAK may force the client back to  INIT  state,
     allowing  it  to  then proceed to obtain a valid DHCP lease.
     However, note that many clients  will  ignore  the  DHCPNAK,
     instead  continuing  to use the IP address they believe they
     have leased, until they believe the lease expires.

---

If a client obtains a DHCP lease (or a dynamically-assigned IP address via
BootP), then you later change bootptab so this client identifier or hardware
address is tagged with the ':de:' tag (Deny Client), the existing assignment was
not being invalidated. We now invalidate the existing assignment.

---

Added a new ':dd:' tag (Deny client dynamically-assigned IP addresses).
Here is the relevant section from the bootptab man page:

     The dd tag is strictly a boolean tag; it does not  take  the
     usual  equals-sign  and  value.  It may only be specified in
     entries which contain a hardware address or client  identif-
     ier.   Its  presence  indicates special handling for packets
     received from this client's hardware address or client iden-
     tifier;  the intent is to never award a dynamically-assigned
     IP address to this client, even if  it  would  otherwise  be
     eligible  for one. It takes precedence over the access flags
     that might be specified in the network statement within  the
     dhcpd.conf  file,  and also takes precedence over any ro
     that might be specified.  It has no  effect  on  awarding  a
     static IP address to this client.

---

We could crash when trying to read the lastbindings from disk on any platform
that treats 'char' as a signed type.

Within a client's lastbinding record on disk, four fields are variable-length:
the Client ID, the Client Hardware Address, the (optional) vend field, and the
(optional) user field. If the length of any of these fields was greater than
127, we eventually misinterpreted the field length as a very large number. We
tried to malloc() a huge amount of memory to store the field, possibly failing
there. If the malloc() succeeded, we'd typically fail as we tried to bcopy()
more data that we had. Once we got into this state, restarting the server
would not help, as the same lastbindings data would consistently cause the
same failure.

This wasn't seen often, because of the four fields that could trigger the
problem, the first two are normally quite short, and the latter two are usually
shorter than 127 bytes (when present at all). The problem would be triggered
when some client had a vend or user field > 127 bytes.

A short-term workaround was to discard the lastbindings data file containing the
problematic data. (Or more likely, discard all the lastbindings data files.)

We no longer misinterpret the field length.

---

Clarify some of the messages we log by adding the IP address in question.

---

Added support for BootP/DHCP options:

  Option Tag
  Code   Name Description
  ----------------------------------------------------------
  19     if   IP Forwarding Enable/Disable
  20     cr   Non-Local Source Routing Enable/Disable
  23     tt   Default IP Time-to-live (TTL)
  27     sl   All Subnets are Local
  29     md   Perform Mask Discovery
  30     mu   Mask Supplier
  32     rs   Router Solicitation Address
  34     te   Trailer Encapsulation
  36     en   Ethernet Encapsulation
  37     tl   TCP Default TTL
  39     kg   TCP Keepalive Garbage
  45     nd   NetBIOS over TCP/IP Datagram Distribution Server
  48     xf   X Windows System Font Server
  49     xd   X Windows System Display Manager
  64     pd   Network Information Service+ (NIS+) Domain
  65     ps   Network Information Service+ (NIS+) Servers
  69     ma   Simple Mail Transport Protocol (SMTP) Server
  70     po   Post Office Protocol (POP3) Server
  71     nn   Network News Transport Protocol (NNTP) Server
  72     ww   default World Wide Web (WWW) Server
  73     fi   default Finger Server
  74     ir   default Internet Relay Chat (IRC) Server

--

Fix Makefile.in to properly list dependancies for dynamic.o.

---


Update configure to check for definition of struct ortentry{}. If we decide to
add a route for the broadcast address, we make use of ortentry{] if it is
defined, else we use rtentry{}. This may improve portability to systems that
have redefined rtentry{} to something very different (e.g. FreeBSD).

(Based on a (different) patch submitted by Howard Harvey <h2 at canuck dot com>.)

---

Replace config.guess with latest version (2002-03-20) from GNU.

Replace config.sub with latest version (2002-04-26) from GNU.

---

If any generic (Txxx) tag specified for an entry did not fit into a
BOOTPREPLY packet, sometimes we failed to log that the option didn't
fit.

---

Added a new feature to filter the options inserted into the "vendor
options" field in a BOOTPREPLY. Here is the relevant section from the
bootptab(5) man page:


FILTERING BOOTPREPLY VENDOR OPTIONS

     The be and bi tags can be used to filter  the  options  that
     may  be returned in the "vendor options" field of a BOOTPRE-
     PLY.

     The  "vendor  options"  field  in  a  BOOTPREPLY  packet  is
     (strictly  speaking) limited to 64 bytes, much less than the
     field in a DHCP response packet.  If you  have  specified  a
     significant amount of data in a bootptab entry, there may be
     too much to fit into the packet if the client speaks  BootP.
     The  be  and  bi  tags  can  help, by letting you filter the
     options that we will try to insert into the BOOTPREPLY.

     These tags only apply to replies sent  to  clients  speaking
     BOOTP  (not  DHCP) that choose to use of the RFC1048 cookie.
     Either tag takes a value which is an ASCII string surrounded
     by  double  quotes  (").   The value consists of whitespace-
     delimited tag names  (including  generic  tag  names);  e.g.
     be="lp lg nt T144".

     If the be tag is specified, then any elements  specified  in
     its  list  will be excluded from a BOOTPREPLY vendor options
     field.  If the bi tag is specified, then  any  elements  not
     specified  in  its  list  will be excluded from a BOOTPREPLY
     vendor options field.  (That is, be and bi act as filters on
     our reply.)

     You may not specify both be and  bi  in  the  same  bootptab
     entry.  (If the entry has inherited one of these tags from a
     template, cancel it (e.g. be@)  before  applying  the  other
     tag.)

     Because be and bi tags apply to an IP address (rather than a
     hardware address or client identifier), they only make sense
     to specify in an entry that has an IP address, or  an  entry
     that  is used as a template for other another entry that has
     an IP address.

     If nr is specified in  combination  with  be  (or  bi),  the
     filtering specified by be (or bi) takes precedence.

     The tag names specified within a be  or  bi  list  need  not
     appear elsewhere in the bootptab entry.

     Do not specify a tag in a be or bi list  using  the  generic
     (Txxx)  syntax  if  the  tag has a well-defined bootptab tag
     name; if you do, the results may be unpredictable.

     It is an error to specify in a be or bi list any  tag  names
     which  do  not  correspond  to an option that might actually
     appear in a BOOTPREPLY "vendor options" field.  E.g. because
     any  bootfile  name would appear elsewhere in the BOOTPREPLY
     packet, it is an error to specify bf as an element with a be
     or  bi list.  The same is true for tag names that correspond
     to directives that modify the behavior of the server  itself
     (e.g.  de).

     We do not  permit  you  to  filter  a  few  options  from  a
     BOOTPREPLY's  vendor  options  field.   They include: subnet
     mask, router addresses, extension file, pad, end.

---

Fixed the bug that caused a generic tag to be left out of a DHCP reply packet
when the 'nr' option was specified in the bootptab entry.

(We still have the bug that causes a generic tag to be left out of a DHCP reply
packet when the client specifically requests that tag via a Parameter Request
List option, if the 'nr' tag is not specified in the bootptab entry.)

---

Attempting to specify generic tag T0 or T225 is now a syntax error. The generic
tag syntax (Txxx=value) doesn't support options that have no length byte.

---

Parsing of generic tags (Txxx) in bootptab is stricter.

If you specify an ASCII (not hex) value for the tag, you must surround it in
double-quotes, as the bootptab man page specifies.

In the past, leaving out the quotes appeared to work. Now, if you specify an
ASCII value without double-quotes, it will be interpreted as a hex value.

E.g. the following will not work anymore:
   T200=foo

Instead write:
  T200="foo"

This only affects generic (Txxx) tags.  Other tags that
accepted unquoted ASCII strings in the past still do.

Note that if do use the incorrect syntax, we will be able to detect a syntax
error if the value begins with characters that cannot possibly be a hex value
(e.g. T200=foo). If the value begins with characters that could be
interpreted as a hex value (e.g. T200=about), we will silently misinterpret
the value as hex.

=========================================================================

Princeton patch 8
October 20, 1999


UPDATING FROM PATCHLEVEL 7

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patches 1, 2, 3, 4, 5, 6, and 7 already applied.

Assuming you have already applied the previous patches, you can apply
this patch as follows:

0. Since this patch introduces new behavior as well as bug fixes, review
the "WHAT'S CHANGED" section below before proceeding.


1. Make a record of any local customizations you have made to the
product, such as changes you have made to 'Makefile' (or possibly 'Makefile.in') 
and 'defaults.h'.  If you did customize either 'Makefile.in' or 'defaults.h' files, 
put the original version back to ensure the patch will apply cleanly.


2. Change to the directory containing the dhcpd source, and feed the patch
file to the 'patch' program.  (The 'patch' program is not supplied here; it
is included with many operating systems, and is freely available from many
software libraries.) E.g. using GNU patch: 'patch -p0 < CMU-dhcpd-3.3.7-PU-patch8'.


3. Please check for, and remove, any of the following obsolete files you find ('patch'
may have removed them for you):

   ./strerror.c


4. Run 'make distclean' to remove old object files, Makefiles and configuration info.


5. If you had previously customized any 'Makefile.in' files (as opposed to
customizing any 'Makefile' files) , now's the time to re-apply your customizations
if necessary.  (You *did* make a record of them, right?)  

Most of the definitions that used to be in Makefile.in have moved to defaults.h,
so you may not need to make any changes to any 'Makefile.in' files at this time.

Before re-apply any of your old customizations, first check to see if
you can now accomplish what you need with a commandline option instead
of a compile-time definition; most defaults and features that
once required a compile-time definition can now be overridden
using commandline options.  Commandline options are covered in the
in the dhcpd.8 man page.

If you do change any 'Makefile.in' files, save the originals first,
so you'll have clean copies available when it comes time to apply the next
patch.


6. Run './configure' to figure out your system's configuration and
generate new 'Makefile' files from the 'Makefile.in' files.


7. If you had previously customized any 'Makefile' files (as opposed
to any 'Makefile.in' files), now's the time to re-apply your customizations.
if necessary.  (You *did* make a record of them, right?)

Most of the definitions that used to be in 'Makefile' files have moved to defaults.h,
so you may not need to make any changes to 'Makefile' files at this time.

Before re-apply any of your old customizations, first check to see if
you can now accomplish what you need with a commandline option instead
of a compile-time definition; most defaults and features that
once required a compile-time definition can now be overridden
using commandline options.  Commandline options are covered in the
dhcpd.8 man page.


8. Examine the 'defaults.h' file and customize it if necessary.  This
file now contains many of the definitions that previously lived in
Makefile.in.

Avoid changing items that can also be set using a commandline option.

If you do change the 'defaults.h file, save the original first,
so you'll have a clean copy available when it comes time to apply the next
patch.


9. Run 'make' to compile the program.  If you receive any compile-time
errors, review the INSTALL document for tips.


10. Kill any running dhcpd, then install the new dhcpd executable.
(It often lives in /etc/dhcpd or /usr/local/etc/dhcpd, but you may 
install it elsewhere.)  You'll probably want to back up your old
dhcpd executable before installing the new one.


11. Optionally update any startup script you may use to take advantage of new
commandline options added in this patch.


12. Optionally update your bootptab file to take advantage of new tags added in
this patch.


13. Optionally update your dhcpd.conf file to take advantage of new configuration
features added in this patch.


14. Start the new dhcpd executable.


15. Optionally install the new dhcpd.8, bootptab.5, and dhcpd.conf.5
man pages manually.


---------------------------------------------------------------------

BUILDING FROM SCRATCH

You can get the current version of the source from 
      http://www.princeton.edu/~irwin/dhcpd.html

Then see the INSTALL document for instructions.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I'm presently
compiling and running on Solaris 2.6 SPARC systems, compiling with
gcc 2.95.1.

---------------------------------------------------------------------

WHAT'S CHANGED

Changes since PU patch 7:

---

The SNMP support is no longer included at compile-time by default. 
If you use the SNMP portion of the package, you can still include it.

I made this change because I suspect most folks aren't using the SNMP
support in this package, and would probably be better off (and safer)
not having an unecessary listener on their machine.  The SNMP support
in the package (an SNMP agent serving a custom DHCP MIB, and 'dhcpcmd',
an SNMP management client) was never well-documented in this package.
The SNMP portion of the code may need some porting to be able to compile 
on some systems, something I'm not inclined to do.

If you want to include the SNMP support, edit the top-level Makefile.
Look for the SNMP section; there's a block of definitions to uncomment
which will cause SNMP support to be added.  (You'll probably want to
edit 'Makefile.in' instead of 'Makefile', so your change will be preserved
across repeated runs of 'configure'.   Be sure to run 'configure' after
editing 'Makefile.in', and if you've made before, also run 'make clean'
before remaking.)

---

If SNMP support has been included at compile-time, you
can still disable the SNMP agent at run-time by specifying an SNMP
listening port of 0 (using the -p option).

---

One of the messages produced when Compact Messages (-C) is enabled
has changed.  When we received a DHCPREQUEST, we logged:

DHCPREQUEST  hhhhhhhhhhhh [g.g.g.g]: request r.r.r.r

Where 'hhhhhhhhhhhh' was the chaddr, 'g.g.g.g' was the giaddr,
and 'r.r.r.r' was the Requested IP Address option (0.0.0.0 if
not present).  When the client is in renewing or rebinding state,
the Requested IP Address is not specified by the client, but the
ciaddr is.  So the message is now one of the following:

DHCPREQUEST  hhhhhhhhhhhh [g.g.g.g]: request r.r.r.r
DHCPREQUEST  hhhhhhhhhhhh [g.g.g.g]: request c.c.c.c
DHCPREQUEST  hhhhhhhhhhhh [g.g.g.g]: request c.c.c.c/r.r.r.r

(where 'c.c.c.c' is the ciaddr)

If the ciaddr is 0.0.0.0, the first form is still used.
Otherwise, the second or third form is used; the second form
is used when the Requested IP Address option is unspecified
(or is mis-specified as 0.0.0.0), while the third form is
used if the Requested IP Address option is specified and nonzero.
(Bruce Hudson <hudson at Snoopy dot UCIS dot Dal dot Ca>)

---

As suggested by Bruce Hudson <hudson at Snoopy dot UCIS dot Dal dot Ca>, 
accomodate certain clients that erroneously include
the "Server IP Address" option in their DHCPREQUEST packets when
they are in REBINDING state.

This is done using the new "Allow 'Server IP Address' Option in
RENEWAL/REBINDING States" feature, enabled with the -R option.

Here is the info from the new man page section:

     Specifying the -R commandline  option  turns  on  the  Allow
     'Server  IP  Address'  Option  in  RENEWAL/REBINDING  States
     feature.

     The DHCP specification says that  DHCPREQUEST  packets  from
     clients  in  INIT-REBOOT,  RENEWING or REBINDING states MUST
     NOT contain the Server IP Address option, while  DHCPREQUEST
     packets from clients in the SELECTING state MUST contain the
     Server IP Address Option.  Some DHCP clients (which  report-
     edly  include Windows 95) violate this by including a Server
     IP Address option in DHCPREQUEST packets when  they  are  in
     the  REBINDING state.  That causes the server to believe the
     client is in the SELECTING state, and act accordingly.

     If you enable  the  Allow  'Server  IP  Address'  Option  in
     RENEWAL/REBINDING  States  feature,  the  server attempts to
     recognize these erroneous packets, and fix them by  ignoring
     the Server IP Address option.

     The erroneous DHCPREQUEST packets are characterized as those
     which  meet  the  following  criteria:  they contain a (non-
     zero) Server IP Address option,  AND  they  do  not  have  a
     Requested IP Address option, AND they have a non-zero ciaddr
     header field, AND the server presently has a binding for the
     Client  Identifier AND the binding for the Client Identifier
     is for the same IP address as the ciaddr.

     Note that the first  criteria  above  is  the  inappropriate
     option  included by the broken client.  The second and third
     criteria above are what would tell us that the client is  in
     the  RENEWING or REBINDING states, instead of INIT-REBOOT if
     the first inappropriate option were not present.  The fourth
     and  fifth  criteria  are  an attempt to limit the incorrect
     decisions we could make in the event we receive an erroneous
     (by  definition)  packet  which  meets  the  other criteria.
     (Since once we treat the client  as  RENEWING/REBINDING,  we
     may  very  well  send  a DHCPNAK; we want to avoid being too
     liberal in deciding packets belong in this  category,  espe-
     cially as we may be only one of several DHCP servers.)

     Note that a side effect of including the  fourth  and  fifth
     criteria  is  that  this  feature will not be able to help a
     client which is bound to another DHCP server and  is  trying
     to  rebind.  As  a  result,  this feature will only help the
     client who is bound to us and is trying to  rebind  (presum-
     ably  because the client did not succeed in renewing with us
     earlier).  (And as a  result,  enabling  the  Renew  Unbound
     Statics feature will not help in this case.)

     This feature has not been  tested  extensively,  and  (deli-
     berately)  causes  the server to violate spec, so you should
     treat it as "experimental" and only enable it with caution.

---

Added this suggestion to the INSTALL document:

As a security measure, you may wish to ensure no one from outside your site can
send packets to the dhcp server.  If you have a firewall router, block incoming UDP
packets destined to the server's port 161 (the bootp/dhcp server port).  (This may
not be feasible if the same router functions as a bootp relay agent.)

---

The OpenBSD 2.4 release notes include some patches to the old bootpd
program, which is a parent of dhcpd 3.3.7.  Some of the bugs in those
release notes apply to dhcpd, so I've applied corresponding fixes here:

The undocumented YORK_EX_OPTION compile-time definition allows you
to specify an "ex" tag in a bootptab entry.  The value of that tag
is the name of a command to run when we receive a BOOTPREQUEST
from that client.  The command is run with the entry's hostname
as its sole argument, and is run in the background.  If the command
and hostname were too large for a buffer, we overflowed the buffer.
Now we issue an error message instead (we don't try to run the
command).

When we need to respond to a client on a local wire, we have to
prime the IP ARP cache.
If we don't have stream ioctls (USE_STREAM_IOCTLS is not defined), 
we do this by calling the 'arp' command with appropriate args.
If the command was too large for a buffer, we overflowed the buffer.
Now we issue an error message instead, and don't try to prime
the arp cache (we probably won't be able to respond to this client).


---

When trying to assign a dynamic IP address, if we discover the address
is simultaneously in a pool's free list AND in the current bindings
(i.e. an inconsistency in our hash tables), one of the diagnostics we
produce was wrong.  We compared the poolname for the free list and
the bound IP address; if they were different, we SHOULD have logged:

  ...Check the conf file for 'network' statements with overlapping IP ranges

but instead we logged:

   ...The bound IP address is listed as being in pool foo
   ...but was found on the free list for pool foo
   ...This suggests the conf file has 'network' statements with overlapping IP ranges


(from bug reported by Juan Courcoul <courcoul at campus dot qro dot itesm dot mx>)

---

We could allow our hashtables to become inconsistent, so that a
dynamic IP address would simultaneously appear in a pool's free list
AND in the current bindings.  

This could happen if we received a DHCPREQUEST from a client in the
INIT-REBOOT state, and the Requested IP Address was for a dynamic
IP address that this client was previously bound to, but the
lease had expired, BUT the garbage collection interval hadn't yet
arrived (so the expired lease was still in our bound hashtables).

Once the hash tables become inconsistent, anything can go wrong.
Since the dynamic address is still on the pool's free list, if we
later attempted to assign it to a client, we'd log an error:

    Tried to assign an ip which already had a binding 1.2.3.4
    ...will not try to assign this address

(from bug reported by Juan Courcoul <courcoul at campus at qro at itesm at mx>)

---

Updated TODO to reflect that we fail to compile on some IRIX platforms
(reported by  Kit-pui Wong <kpwong at psy dot cuhk dot edu dot hk>).  This is due to
a portability bug we have in handling rtentry.  Updated INSTALL to
provide a workaround.

Similar problem reported by Howard Harvey <h2 at canuck dot com> for NetBSD.

---

Corrected dhcpd.8 man page to reflect that when Check File Access is enabled
(as it is by default), it also affects processing 
when the bootfile field in the client's packet is null, (for both BOOTP and DHCP).
In this situation, if the bootptab specifies a bootfile, then if 
Check File Access is enabled, the bootfile will only be inserted into
a response packet if the bootfile is present and accessible on the server.
Otherwise the response packet will have a null bootfile file.

---

When we dumped the in-memory bindings or bootptab to a file, entries 
with generic tags did not print correctly.  The generic tag data was
printed at the end of the entry, after the comment lines associated
with the entry.  The line-continuation layout was also wrong.  Now
the generic tags print near the end of the entry, before the comment lines.

---

I added a -m option.  Here's the relevant man page section:

     -m my_ip_addr
          Override the my_ip_addr value used  internally  by  the
          server  to  indicate  the server host's own IP address.
          Normally my_ip_addr is computed by the server by  look-
          ing  up  hostname  (see  below).  You can instead force
          my_ip_addr to a fixed value using  this  option.   This
          option should almost never be used; specifying an inap-
          popriate value will cause the server (and  clients)  to
          malfunction.   It may be helpful if the server host has
          a problem using gethostbyname(3), or if the server host
          has virtual interfaces (in concert with the -S option).

---

I added the new "unregistered" access flag for the "network" statement
that appears in the dhcpd.conf file.

Specify the "unregistered" flag to cause the dynamic IP address pool
to be restricted to clients whose Client Identifier does NOT appear
somewhere in the bootptab file.

You must continue to specify exactly one of the access flags:
"bootp", "dhcp", or "both".  You may also specify zero or one of the
access flags: "registered", "unregistered", or "roaming".

---

If you handed a lease to a client, then before the lease expires, changed
the bootptab file to specify the ":de" (Deny Service) for the client, 
then we received a DHCPREQUEST from the client in RENEWING or REBINDING state,
we correctly sent a DHCPNAK to the client.  But we also discarded the current
binding for the client, on the assumption that the NAK drove the client back to
INIT state.  That's not a valid assumption; some clients continue using their
existing lease until its expiration time arrives.  We no longer discard the
binding in this case.

--- 

Documented a long-standing bug:

If the server leases an IP address to client, then before the lease expires,
the bootptab and/or dhcpd.conf files are changed to cause that binding to 
become invalid, the server will discard the binding when it re-reads the files 
(at server re-start or upon receipt of a packet).  However, the client may still 
be using the IP address until the lease expires; this can be a particular problem 
if the IP address is a member of a dynamic pool, or has been statically re-allocated 
to another client.

---

If the last option on the commandline was simply "-d" (with no number following it),
it was reported as an invalid debuglevel.

---

Added an optional log_assignments-level value to the existing -a option.  
If you specify a value of 1, you get the same behavior that the -a
option produced in the past: a message is produced whenever the server assigns an IP
address to a client.  If you specify a value of 2, a message is added
whenever the server renews an existing DHCP lease.  If you specify a value
of 3, a message is added whenever the server makes an offer for a DHCP lease.

If you specify -a with no value (the old syntax), it uses a value
of 1, so you get the old behavior.

The additional messages look like:

RENEWED DHCP STATIC 192.168.1.2 (foo.bar) TO CLIENT (pc12.bar) 01 00 02 03 A4 8B 50 

OFFERRED DHCP DYNAMIC 192.168.1.3 (baz.bar) TO CLIENT (pc13.bar) 01 00 02 03 A4 9B 04


---

Updated configuration scripts from autoconf 2.12 to 2.13.

---

snmpd/alarm.c:  timeradd() is actually a system macro under xBSD.
Renamed to DoTimerAdd() so it can compile and run correctly under NetBSD 1.3.2.
(Howard Harvey <h2 at canuck dot com>)

---

init_interfaces() in getif.c calls max(), which is a macro that is defined on some systems,
but not on others.  Now we define the macro if necessary.  (Howard Harvey <h2 at canuck dot com>)

---

Our reclaration of sys_errlist in several places caused an error on NetBSD 1.3.2.
(Howard Harvey <h2 at canuck dot com>)

Our syserror() replacement was being compiled even if syserror() was available.
We assumed sys_errlist and sys_nerr were available, even if they were not.
We declared sys_errlist and sys_nerr even if they were already declared,
possibly in a conflicting way.  

We now only compile our syserror() replacement if syserror() isn't available.
The configure script now checks to see if sys_errlist and sys_nerr are available,
and if they are declared.  We only use them if they are available, and only declare
them if they are not already declared.  I have moved strerror() from strerror.c 
to my_strerror.c and my_strerror.h.

Some of the new code comes under the GNU General Public License, so that's
been added to the COPYING file.

---

Make snmpd/snmp_vars.c compile on NetBSD 1.3.2.  Surgery to deal with the some of the 
data structure traversals.  Some structure elements changed names so it was necessary 
to ferret them out of their new locations. (Howard Harvey <h2 at canuck dot com>)

---

We now support the "Perform Router Discovery" option (option number 31, long-defined
in RFC 2132).  The bootptab tag is "rd" and it takes a value of a decimal, 
octal, or hexadecimal number.  (The only meaningful values presently defined
are 0 and 1.)

---

We now support the "Static Route" option (option number 33, long-defined
in RFC 2132).  The bootptab tag is "sr" and it takes a whitespace-separated
list of IP addresses.  You must supply an even number of addresses; each
pair is taken as a destination address and a router address.

---

Added an experimental feature to deal in some fashion with "Dynamic DNS."

Here is the new section "Dynamic DNS" section from the dhcp(8) man page:

     This server does not presently support true Dynamic DNS.  It
     is assumed that all IP addresses and associated hostnames in
     the bootptab are already registered in DNS;  i.e.  from  the
     point-of-view  of  DNS,  all  the  A records and PTR records
     associated  with  this  DHCP  server's  leases  are  static,
     regardless  of  whether the DHCP server is leasing addresses
     dynamically to DHCP clients.

     However, this DHCP server presently includes an experimental
     feature  associated with Dynamic DNS.  In future versions of
     this DHCP server, the feature as described in  this  section
     may be removed or changed in incompatible ways.

     The Internet Draft Interaction between DHCP and DNS  <draft-
     ief-dhc-dhcp-dns-10.txt>  specifies  how  DHCP  clients  and
     servers should use Dynamic DNS.

     Some clients now attempt to perform Dynamic DNS by  default.
     In  the current version of this DHCP server, the DHCP client
     probably should not attempt to perform Dynamic DNS,  because
     all  the  DNS  A  records and PTR records associated with IP
     addresses leased by the DHCP server should already be stati-
     cally  defined  in  DNS (static from DNS' point of view, not
     necessarily from the DHCP server's point of view).

     According  to  <draft-ief-dhc-dhcp-dns-10.txt>,  if  a  DHCP
     client  sends  the Client FQDN option to the DHCP server, or
     includes that option number  in  a  Parameter  Request  List
     option,  the  corresponding  response  packet  from the DHCP
     server should include the Client FQDN option (option 81).

     The option in the DHCP server's response is supposed to com-
     municate several pieces of information.  As presently imple-
     mented by this DHCP server, when the server sends  a  Client
     FQDN option to the client, it will contains a flags value of
     0x03, an rcode1 value of 0x00, an rcode2 value of 0x00,  and
     a  domain  name  value equal to the client's fully-qualified
     hostname, in ASCII encoding.

     This response (specifically, a flags value of 0x03) is  sup-
     posed  to tell the DHCP client that it should not attempt to
     use Dynamic  DNS  to  update  its  A  record,  according  to
     <draft-ief-dhc-dhcp-dns-10.txt>.  (That draft also says that
     the client isn't supposed to attempt to use Dynamic  DNS  to
     update  its PTR record; there's nothing defined in the draft
     to allow a DHCP server to actually tell the client  that  it
     should not try to update its PTR record, as it's assumed the
     client will never do this.)

     Unless configured otherwise, we follow the rules in  <draft-
     ief-dhc-dhcp-dns-10.txt> that govern whether the Client FQDN
     option should be sent to the client.  These rules are a  bit
     different than the rules governing whether most other tradi-
     tional options should be  sent  to  clients.   Unlike  other
     options, the presence of Client FQDN option in a packet from
     the DHCP client triggers the  inclusion  of  a  Client  FQDN
     option  in the DHCP server's response. (And as you'd expect,
     the option will also be included in the server's response if
     it  was  present  in  the  client's  Parameter  Request List
     option, like many other options.)  Note  that  this  happens
     even though the client's bootptab(5) entry may contain no cf
     tag.  The value of the Client FQDN option  is  one  that  is
     computed by the server, not specified in the bootptab(5).

     Associated with the feature  is  the  new  cf  tag  for  the
     bootptab(5)  file.  It may only be specified with a value of
     0x00 or 0x01; no other values are presently valid.

     Specify a value of 0x00 to direct the server to never return
     a  Client  FQDN option to this client.  Use this to suppress
     the experimental feature entirely.

     Specify a value of 0x01  to  direct  the  server  to  always
     return  a Client FQDN option to this client, when the nr tag
     has also been set for this client, and the client is  speak-
     ing  DHCP.   The  server  will  also  continue to return the
     Client FQDN option to clients that it normally would had the
     cf tag not been present in the bootptab entry at all.  (Note
     that setting this tag to 0x01 for a  client  that  does  not
     have the nr tag set has no effect.)

     We never return the Client FQDN option to BootP clients.

     In  this  experimental  implementation,  we   deviate   from
     <draft-ief-dhc-dhcp-dns-10.txt>  with regard to the encoding
     of the domain name.  The draft says that if  a  Client  FQDN
     option  specified  by  the  DHCP client had the 'E' flag bit
     set, the Client FQDN option we send  to  the  client  should
     encode  the  domain name field  using DNS-style encoding; if
     the bit was 0, we should encode it in  ASCII.   However,  we
     ignore  the  'E'  flag  sent  by the DHCP client, and always
     encode the domain name field in ASCII.  We do  not  know  if
     that causes any problems for any particular client implemen-
     tations at this time.)

     In this experimental implementation, we are ignoring all the
     information  contained  in  the  Client FQDN option that the
     DHCP client might supply.  We simply return a fixed response
     that means "here's your FQDN, don't try to update DNS."

     We also deviate  from  <draft-ief-dhc-dhcp-dns-10.txt>  with
     regard to the values in rcode1 and rcode2.  The draft speci-
     fies that these fields  in  the  server's  response  to  the
     client  contain  the  return  codes the DHCP server received
     from the DNS  server  when  it  performed  the  Dynamic  DNS
     update(s).   The  draft  specifies  that  if the DHCP server
     sends its response to the DHCP client  without  waiting  for
     the  DNS update to be completed, the server should set these
     field(s) to 0xff.  Since our DHCP server does not intend  to
     ever  perform the Dynamic DNS update, what it should send in
     rcode1 and rcode2 is not well-defined.  We  choose  to  send
     0x00  for  both  fields, which is the return code indicating
     that the Dynamic DNS update  was  completed  without  error.
     While  this  is  not strictly true, it seems the best choice
     given that our present implementation is  designed  only  to
     convince  the  DHCP  client  to  not  attempt to perform any
     Dynamic DNS updates on its own.

---

We used to allow you to erroneously specify null string values for the bootptab
options 'dn' (DNS Domain Name), 'rp' (Root Path), 'ef' (Extensions File),
'yd' (NIS Domain name), and 'sc' (NetBIOS over TCP/IP Scope).

When sent in a response packet's option field, these would result
in the corresponding option to have a 'length' field with a value
of '0'.  This is not legal as per spec.

We no longer allow you to specify null string values in the bootptab
for those options.

In addition, if you did not specify a 'dn' (DNS Domain Name) bootptab
and we try to insert a domain name option in a DHCP response packet, we
used to (and still do) attempt to infer the domain name by grabbing
all but the first component of the bootptab entry's hostname.
(The hostname is the first field in the bootptab entry; it is the
label of the entry.)  But if the hostname has just a single component,
we infer a null domain name.  In that situation, we no longer will
send the null domain name.

(Based on report from Debbie Andrews <dnd at po dot cwru dot edu>, 
Bob Beck <rlb5 at po at cwru dot edu> and Jim Campbell <jimcam at microsoft dot com>.)

---

Howard Harvey <h2 at canuck dot com> has offered to act as a contact
for "those venturesome souls who want to make it run under the
BSDs or any other operating system."


=========================================================================

Princeton patch 7
February 15 1999


UPDATING FROM PATCHLEVEL 6

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patches 1, 2, 3, 4, 5, and 6 already applied.

Assuming you have already applied the previous patches, you can apply
this patch as follows:

1. Make a record of any local customizations you have made to the
product, such as changes you have made to 'Makefile' (or possibly
'Makefile.in').  If you did customize any 'Makefile.in' files, put
the original version back to ensure the patch will apply cleanly.


2. Change to the directory containing the dhcpd source, and feed the patch
file to the 'patch' program.  (The 'patch' program is not supplied here; it
is included with many operating systems, and is freely available from many
software libraries.) E.g. using GNU patch: 'patch -p0 < CMU-dhcpd-3.3.7-PU-patch7'.


3. Please check for and remove any of the following obsolete files you find ('patch'
may have removed them for you):

   ./syslog.h
   ./man/bootpef.8
   ./man/bootptest.8
   ./sample/dhcpd.conf.sample
   ./sample/dhcpd.conf.sample2
   ./Announce.old
   ./README.old
   ./Changes
   ./Installation
   ./README.PRINCETON
   ./README.PRINCETON1
   ./README.PRINCETON2
   ./README.PRINCETON3
   ./README.PRINCETON4
   ./README.PRINCETON5
   ./README.PRINCETON6


4. Run 'make distclean' to remove old object files, Makefiles and configuration info.


5. If you had previously customized any 'Makefile.in' files (as opposed to
customizing any 'Makefile' files) , now's the time to re-apply your customizations
if necessary.  (You *did* make a record of them, right?)  

Most of the definitions that used to be in Makefile.in have moved to defaults.h,
so you may not need to make any changes to any 'Makefile.in' files at this time.

Before re-apply any of your old customizations, first check to see if
you can now accomplish what you need with a commandline option instead
of a compile-time definition; most defaults and features that
previously required a compile-time definition can now be overridden
using commandline options.  New commandline options are covered in the
WHAT'S CHANGED section below (and appear in the dhcpd.8 man page, of course).

If you do change any 'Makefile.in' files, save the originals first,
so you'll have clean copies available when it comes time to apply the next
patch.


6. Run './configure' to figure out your system's configuration and
generate new 'Makefile' files from the 'Makefile.in' files.


7. If you had previously customized any 'Makefile' files (as opposed
to any 'Makefile.in' files), now's the time to re-apply your customizations.
if necessary.  (You *did* make a record of them, right?)

Most of the definitions that used to be in 'Makefile' files have moved to defaults.h,
so you may not need to make any changes to 'Makefile' files at this time.

Before re-apply any of your old customizations, first check to see if
you can now accomplish what you need with a commandline option instead
of a compile-time definition; most defaults and features that
previously required a compile-time definition can now be overridden
using commandline options.  New commandline options are covered in the
WHAT'S CHANGED section below (and appear in the dhcpd.8 man page, of course).


8. Examine the 'defaults.h' file and customize it if necessary.  This
file now contains many of the definitions that previously lived in
Makefile.in.

Avoid changing items that can also be set using a commandline option.

If you do change the 'defaults.h file, save the original first,
so you'll have a clean copy available when it comes time to apply the next
patch.


9. Run 'make' to compile the program.  If you receive any compile-time
errors, review the INSTALL document for tips.


10. Kill any running dhcpd, then install the new dhcpd executable.
(It often lives in /etc/dhcpd or /usr/local/etc/dhcpd, but you may 
install it elsewhere.)  You'll probably want to back up your old
dhcpd executable before installing the new one.


11. Update any startup script you may use to take advantage of new
commandline options added in this patch.


12. Start the new dhcpd executable.


13. Optionally install the new dhcpd.8, bootptab.5, and dhcpd.conf.5
man pages manually.

---------------------------------------------------------------------

BUILDING FROM SCRATCH

You can get the current version of the source from 
      http://www.princeton.edu/~irwin/dhcpd.html

Then see the INSTALL document for instructions.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I'm presently
compiling and running on Solaris 2.5.1 and 2.6 SPARC systems.

---------------------------------------------------------------------

WHAT'S CHANGED

Changes since PU patch 6:

---

I've received permission from Carnegie Mellon University to distribute
their source, so you can now download the pre-patched source.  If you
prefer, you can still download just the patches, of course, and
apply them yourself.

---

A wider variety of precompiled versions of dhcpd for Solaris on
SPARC and i86pc architectures has been made available by 
mark at sunsite dot unc dot edu (mark at zang dot com).  Visit:

http://sunsite.unc.edu/pub/packages/solaris/sparc
 ftp://sunsite.unc.edu/pub/packages/solaris/sparc

(Look for a filename that starts with 'dhcp' and check to see what
version number (patchlevel) it includes.)

---

Previously each Princeton patch had its own README file, containing
its release notes, any patch instructions, legal notice, etc.

I've removed these files (./README.PRINCETON*).  The current
and previous release notes are now in the new RELEASE_NOTES file,
in reverse chronological order.  The legal notices are now in
the new COPYING file.

Removed obsolete documentation:
./Changes
./Announce.old
./README.old
./TODO
./man/bootpef.8

Replaced obsolete ./README with a new version.

The "Installation" file has been renamed "INSTALL" and tidied up.

---

Removed "-I/usr/include" from CDEFS in the top-level Makefile, finally.
It doesn't belong there.  

This addresses the long-standing ugliness that caused the familiar 
compile-time error: "__builtin_va_alist undeclared" in report.c.  This 
also addresses the "ioctl(SIOCGIFCONF): not supported" runtime error.

If you now get "__builtin_va_alist undeclared", fix your installation of
gcc.  Chances are the fixed include files that gcc needs were not installed.

For more details, search the Solaris FAQ for 'builtin_va_alist':
  http://www.fwi.uva.nl/pub/solaris/solaris2.html

---

The fake 'syslog.h' file (which provided some definitions in case the
system didn't provide syslog.h) has been removed.  It has been replaced
with 'my_syslog.h' which simply includes the real syslog.h if 'configure'
found it, else it provides those definitions we need.  All other files
that did #include <syslog.h> or #include "syslog.h" have been changed
to #include "my_syslog.h".

The -I$(top_srcdir) has been removed from CFLAGS in the top-level Makefile.
Its purpose was to cause the fake syslog.h to be found if the system version
was missing.  This is no longer necessary.

Note that you should no longer need to use the old workaround of putting
"-idirafter ." in CDEFS.

---

By default the server did not write a pidfile (although you could override
this by defining the PID_FILE compile-time option to an absolute pathname).
Now PID_FILE is defined by default at compile-time to /etc/dhcpd.pid.
You can override the absolute pathname with the new command-line -P option.
It is a fatal error if the server cannot write its pidfile.

---

If you do not specify a current working directory using the -c command-line
option, the current working directory will default to /.  (Previously,
the server simply left its current working directory unchanged.)

This change to the default was made so that by default, the daemon
does not keep open a directory that you may wish to unmount later.

If you haven't been specifying a -c option, you may now need to,
if your dhcp server host is also the home of client bootfiles.

This is because the current working directory plays a role 
in interpreting client bootfile names.  If a client bootfile name is 
specified as a relative pathname, and the server needs to check the
existance or size of the bootfile, the bootfile pathname 
is taken relative to the server's current working directory.
(Existance checking for bootfiles is turned on by default; it
is controlled by the compile-time definition CHECK_FILE_ACCESS in 
the Makefile.)

So if your dhcp server host is also the home of  client bootfiles, and 
in the past you cd'd to the bootfile directory before starting the dhcp 
server, then now you will need to specify the bootfile directory using
the -c option when starting the server.

It is now a fatal error if the server cannot change to the specified (or default)
current working directory.

---

When a DHCP client specified a Client Identifier option which does not
correspond to its htype/chaddr, we log a message indicating the mismatch.
(As before, we will still honor the Client Identifier specified by the client.)

---

Added -I option, to cause the server to ignore any Client Identifier
specified by DHCP clients.  This is based on an earlier suggestion by Mel Lew
<melvin at columbia dot edu>.

When you specify this option, the server proceeds as if the client
did not specify any Client Identifier option; the server constructs
a cliid by concatenating the htype and haddr fields.  Note that since
the Client Identifier option is entirely ignored (it is not parsed),
no messages indicating problems with its value are logged.

This is useful if you have clients who specify garbage Client Identifier
values.  Note that specifying this option produces behavior that violates
the DHCP specification.

---

An error message produced when we try to assign a dynamic IP
address which is a member of multiple pools (due to erroneous
overlapping pools definitions in the dhcpd.conf file) did not
print the names of the pools involved.  (This message was also
triggered by another bug described below, in which we sometimes
neglected to remove a dynamic address from a pool's free list.)

---

Although we ignore DHCPINFORM messages, we were leaking memory each time
we received one.

---

haddrtoa() did not function correctly if called with hlen=0.
(E.g. when a client tried to tell us its hardware address
of Cliid had a length of 0.)
Instead of returning a ptr to a null string, it returned
a pointer to the last value it returned, and overwrote one
byte of memory residing immediately below its (static)
storage.  This memory corruption eventually led to 
random errors and crashes.

---

We failed to update our notion of the lease expiration time when
we received a DHCPREQUEST from a currently-bound client in the
INIT-REBOOT state.  

We sent the client a good DHCPACK with the
correct (extended) lease expiration time, and even logged the 
correct (extended) lease expiration time (if you had debugging
on high enough).  But the lease expiration time stored in our
bindings data was not updated.  

As a result, if that time
arrived (before any other transaction occurred that would
cause the binding to be updated or deleted), the server
expired the lease.  The client would continue to use the lease,
of course.  

For static IP addresses you might not notice the problem,
because if the client later sends a DHCPREQUEST to RENEW the lease,
we'll create a new lease if the address is for a static IP address
and "Renew Unbound Statics" is enabled.   For dynamic IP addresses
it is more noticable, since we may try to assign the free (from our
point of view) dynamic IP address to someone else, and possibly
notice it still in-use when we PING it.

(Problem reported by Juan Courcoul <courcoul at campus dot qro dot itesm dot mx>)

---

We failed to update the free list for a pool of dynamic IP addresses
when we decided to grant one of these addresses to a client
sending us a DHCPREQUEST in INIT-REBOOT state, if our bindings data
indicated that client was not presently bound.  As a result, the
dynamic IP address was granted to the client AND remained in the
free list.  When trying to assign a dynamic address from this pool
to another client, we could discover this entry, then complain that
it was both in the free list AND in the current bindings.  We'd
log the discrepancy:

Tried to assign an ip which already had a binding a.b.c.d
...will not try to assign this address
...The bound IP address is listed as being in pool
...but was found on the free list for pool
...This suggests the conf file has 'network' statements with overlapping IP ranges.

(Since we did notice the discrepancy, we correctly avoided re-assigning
this address.)

(Problem reported by Juan Courcoul <courcoul at campus dot qro dot itesm dot mx>)

---

When we detect a mismatch between a the Client ID option specified by a DHCP client
and the chaddr field, the message we log could fail to include the chaddr value; e.g.:

   Client ID option (00 00 00 00 00 00 00 ) doesn't correspond to chaddr ()

Now we should report the chaddr value more often.  (There are still times
we aren't reporting the chaddr.)

---

When dhcp_opts() logs an error message, it now appends the IPsrc value from
the offending packet.  This info was already being logged back when
the packet was received, if your debuglevel is high enough, but it's
more convenient to have it right on the error message as well.

---

Y2K: I am not aware of any Y2K problems with the code.
Brandon Hume of Dalhousie University has reviewed the code;
his findings are at:
   http://noc.dal.ca/CommServ/reports/dhcpd_y2k.html


---

When parsing the bootp header fields 'file' and 'sname' (bp->bp_file
and bp->bp_sname), we now set the final byte of these fields to NUL, 
to guard against buffer overflow attacks.  According to RFC, these 
fields sent by the client are supposed to either be null, or a null-terminated
string; it should therefore be safe to overwrite the final byte
with NUL.

---

report() allocated a static 128-byte buffer for constructing
messages; this has been increased to 256 to accomodate larger
messages report() may be called with.  vsprintf() call replaced
with vsnprintf() (where available) to guard against buffer overflow.

---

When we scanned interfaces at startup, if we detected an interface
that was not UP and skipped it, we could log a message like:
"interface qe1, skipping (not IPv4)".  Now the message we log
is simply "interface qe1, skipping".  (In init_interfaces(), the test
for address family has moved to after the test for appropriate
interface flags.)

---

If the same IP address was erroneously specified in multiple bootptab entries,
readtab() would go ahead and create inconsistent in-memory bootptab hashtables.
This could produce all sorts of runtime problems.  For example, if you had two
clients assigned the same static address, if one client issues a DHCPDISCOVER 
at the same time the other client already has a lease on the address you could see:

        dhcp_discover(): cliid () assigned a static IP (192.168.84.11) in bootptab, cliid not found in boundhshtbl, but this IP *FOUND* in ipboundhshtbl!
        the unexpected entry found in ipboundhshtbl had the cliid 01 08 C0 6F 89 22 A3
        freeing unexpected binding found in ipboundhshtbl

We never did support specifying the same IP address, hardware address, client identifier,
or entry name in multiple bootptab entries.  The behavior when you did so was not defined.

Now readtab() is more careful when it reads the bootptab file.  It checks for duplicate
entry names, IP addresses, hardware address, and client IDs before attempting to insert
any of the parsed data into the appropriate hash tables.  When a duplicate is found, an error
is logged at LOG_ERR, and the entire entry containing the duplicate value is skipped.

Some other error messages produced by readtab() were clarified or moved from LOG_NOTICE to
LOG_ERR.

---

When running at high debug levels, the following spurious message was produced when we 
received a PAD option (option 0) in a client's Parameter Request List option:

        "ignoring unknown or unexpected option (0) in client's Parameter Request List option"

We no longer produce this message.

---

Added new -B commandline option, to allow you to specify a different bindings
dump file, overridding the default /tmp/bind.dump.  The name of the bindings
dump file is now included in the log message at the conclusion of a successful
bindings dump.

---

You can now run the server with an effective uid and gid other than root.
However, it must still be started as root, and retains its real uid and gid.

Here is the new information from the manual page:

RUNNING AS AN UNPRIVILEGED USER

     The server must be started as root.  It needs to be able  to
     perform several privileged operations at startup time.  How-
     ever, after it completes these  operations,  it  only  needs
     root  privileges  occasionally.   (It  needs root privileges
     whenever it needs to insert entries into the host's  IP  ARP
     table to send a packet to a host on a directly-attached net-
     work.  It needs root privileges whenever it needs to open  a
     raw  datagram  socket to use to ping a dynamic IP address to
     verify it is not presently in-use before assigning it  to  a
     client.)

     To limit any accidental damage the server  could  do  it  it
     contains bugs, you can specify that the server should change
     its effective uid and/or effective gid  to  something  other
     than  root.   After  performing  some startup operations, it
     will make the change.

     To use this feature, specify the  username  (or  uid)  under
     which  the server should run with the -U option; specify the
     groupname (or gid) under which the server should run with -G
     option.   Note  that this is only supported if the host sup-
     ports seteuid().

     While running, the server may need to manipulate the  host's
     IP  ARP  table  from  time  to  time.  If it has changed its
     effective uid to something other than root's, it  will  tem-
     porarily  change its effective uid back to root's to manipu-
     late the IP ARP table.

     Note that while this feature makes  it  less  convenient  to
     exploit  the  server's root privileges if there are any bugs
     present in the server, it does not provide complete  protec-
     tion, since the server still retains a real uid of root.
     To make best use of this feature, you should probably create
     a  new  user  and  group (assign (assigning a unique uid and
     gid); for the server to use; e.g. user dhcp and group dhcp.

     The server needs  to  be  able  to  read  the  bootptab  and
     dhcpd.conf  files, and needs to be able to read and write in
     the bindings directory. Set the owners/groups and/or permis-
     sions  of  the  files  and  directories above to provide the
     necessary access to the user/group you selected for the dhcp
     server.  Keep in mind that you don't want to allow arbitrary
     users to modify the bootptab and dhcpd.conf files, or  write
     in the bindings directory.

     The server can write bootpd.dump and  bind.dump  files  upon
     receipt of the appropriate signals. Make sure the user/group
     you selected for the dhcp server can write  these  files  if
     you intend to send those signals to the server, and that the
     user that sends these signals has the necessary privilege to
     send those signals.

---

Whenver the server had to write a file, it wasn't as careful as it
should have been about how it created the file for writing.  
This could allow an unprivileged user the opportunity to cause the
server to remove or overwrite any file on the system.

Now we're more careful about how we open files for writing.

(The server creates a pidfile at startup, and upon receipt of USR1 or USR2
signals, creates a bootptab dump file or a bindings dump file.)

---

If we received a signal to dump the current bootptab or bindings
database, and were unable to open the appropriate dump file for
writing, we'd log the error and exit.  Now we log the error and
continue.  Not being able to write a dump file isn't a fatal error.

---

Added a -A option to allow you to disable the "Check File Access"
feature from the commandline.  (Previously you could only disable
it by undefined the CHECK_FILE_ACCESS compile-time definition.)

---

Makefile.in has been cleaned up.

Definitions specific to the program have been moved to the new defaults.h
file, to make maintenance and customization easier.

The definitions in defaults.h (and those remaining in Makefile.in) have
been cleaned up to make it clearer what you might want to edit and what
you should probably just leave alone.  Since almost all the program's
features you can manipulate via compile-time definitions can now *also*
be manipulated via commandline options, most changes you may have made
in the past no longer are necessary.  The major exceptions are
definitions for LOG_FACILITY and DEBUG (in defaults.h) and OPT (in
Makefile.in).

The 'clean' target will also remove core files.
The 'distclean' target will also 'make clean'.

---

In the sample/ directory, obsolete sample file dhcpd.conf.sample" was removed, and
"dhcpd.conf.sample2" was renamed to "dhcpd.conf".  Obsolete man page "bootptab.5"
and "bootptest.8" were deleted.

---

Added a sample SysV-style startup script to the sample/ directory.

---

Added new 'de' (deny client) tag support in bootptab.  Here is the
description from the bootptab man page:

     The de tag is strictly a boolean tag; it does not  take  the
     usual  equals-sign  and  value.  It may only be specified in
     entries which contain a hardware address or client  identif-
     ier.   Its  presence  indicates special handling for packets
     received from this client's hardware address or client iden-
     tifier;  the  intent  is to deny BOOTP and DHCP service from
     this server to the client, without interfering with any ser-
     vice the client may be able to receive from another BOOTP or
     DHCP server.  BOOTPREQUEST and DHCPDISCOVER packets from the
     client  are  ignored.  DHCPREQUEST packets from clients that
     are in  SELECTING  state  are  ignored  (as  usual)  if  the
     packet's  Server  Identifier  Option  does not correspond to
     this server.  For DHCPREQUEST packets from clients that  are
     in  SELECTING  state  with  a  Server Identifier Option that
     specifies this server: if no offer or binding is present for
     this  client identifier we send a DHCPNAK (as usual), but if
     an offer or binding is present for this client identifier we
     send  a  DHCPNAK and discard the binding/offer.  For DHCPRE-
     QUEST packets from clients that are in INIT-REBOOT, if there
     is  not  presently a binding for this client identifier, the
     packet is ignored; if there is presently a binding for  this
     client  identifier,  the  binding is discarded and we send a
     DHCPNAK.  DHCPREQUEST  packets  from  clients  that  are  in
     RENEWING  or  REBINDING (or confused) state, if there is not
     presently a binding for this client identifier,  the  packet
     is  ignored; if there is presently a binding for this client
     identifier, the binding is discarded and we send a DHCPNAK.


You might find this tag useful in the following scenario: you
serve dynamic IP addreses on a network to any client that asks;
the 'network' statement for the pool of dynamic addresses does NOT
contain a "registered" or "roaming" accessflag.  But then you have a 
small collection of client machines to which you do NOT want to serve 
dynamic addresses (e.g. interlopers).  Add them to your bootptab, specifying 
just their hardware addresses and the new 'de' tag.

---
=========================================================================

Princeton Patch 6
July 21 1998


UPDATING FROM PATCHLEVEL 5

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patches 1, 2, 3, 4, and 5 already applied.  

Assuming you have already applied the previous patches, you can apply
this patch as follows:

1. Make a record of any local customizations you have made to the
product, such as changes you have made to 'Makefile' (or possibly
'Makefile.in').

2. Change to the directory containing the dhcpd source, and feed the patch 
file to the 'patch' program.  (The 'patch' program is not supplied here; it 
is included with many operating systems, and is freely available from many 
software libraries.) E.g. using GNU patch: 'patch -p0 < CMU-dhcpd-3.3.7-PU-patch6'.

3. Run 'make clean' to remove old objects.

4. Run 'make distclean' to remove old Makefiles and configuration info.

5. If you had previously customized any 'Makefile.in' files, now's the time to
re-apply your customizations.  (You *did* make a record of them, right?)

6. Run 'configure' to figure out your system's configuration and
generate new Makefiles from the 'Makefile.in' files.

7. If you had previously customized any 'Makefile' files, now's the time
to re-apply your customizations.  (You *did* make a record of them, right?)

8. Run 'make' to compile the program.

9. Kill any running dhcpd, then install the new dhcpd executable.
(It often lives in /etc/dhcpd, but you may install it elsewhere.)

10. Start up the new dhcpd executable.

11. Optionally install the new dhcpd.8, bootptab.5, and dhcpd.conf.5
man pages.

---------------------------------------------------------------------

BUILDING FROM SCRATCH

If you are starting from scratch (you don't already have dhcpd
patchlevel 5 source, then first get and unpack dhcpd 3.3.7 from CMU.
Then change to the directory containing the dhcpd source, and feed each
Princeton patch file to the 'patch' program, in order.  (The 'patch'
program is not supplied here; it is included with many operating
systems, and is freely available from many software libraries.)

Before applying patch 5, issue the following command:
   mkdir tools
After applying patch 5, issue the following command:
   chmod 0555 tools/gen-config

Then see the "Installation" document for instructions about compiling
and installing the software.  Read the dhcpd.8, bootptab.5, and
dhcpd.conf.5 man pages.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I've only
compiled on SunOS 4.1.4 and Solaris 2.5.1, and most of my testing
is on Solaris 2.5.1.

---------------------------------------------------------------------

WHAT'S CHANGED

Changes since PU patch 5:

---

When the same relay agent was listed in more than one 'network'
statement in the dhcpd.conf file, the resulting struct gateway member
of the gwhashtbl was corrupt.  The gw->nets field pointed to freed
memory, instead of to an array of pointers to the names of the pools of
dynamic IP addresses behind this relay agent.  This could cause all
sorts of havoc.

---

The server now supports multiple IP networks on the same wire;
code contributed by Mel Lew <melvin at columbia dot edu>.

Use the new 'proxy' statement in the dhcpd.conf file to 
define the additional IP networks.  The syntax is:

proxy relayAgent-interface-ipaddr secondary-network-number secondary-network-netmask [secondary-network-number secondary-network-netmask]...

The relayAgent-interface-ipaddr is the IP address of a relay agent
already defined in an earlier 'gateway' statement.  The
secondary-network-number and secondary-network-netmask describe the
additional IP network running on the same wire associated with that
earlier 'gateway' statement.  If more IP networks are on that same
wire, you may specify additional pairs of secondary-network-number and
secondary-network-netmask, or you may list them on separate 'proxy'
statements.

If you are also serving pools of dynamic IP addresses on the additional
IP network, you first define the pool as usual, with a 'network'
statement.  The relayagentipaddr and relayagentnetmask that appear in
that 'network' statement should be the relay agent interface's
*primary* IP address (that which appears in a 'gateway' statement),
*not* the secondary IP address, since it's the former that will be
inserted by the relay agent into a relayed packet's 'giaddr' field.

If you are also serving pools of dynamic IP addresses on the additional
IP network, you also specify the poolname on the 'gateway' statement
corresponding to the relay agent.  You don't specify poolnames in
'proxy' statements.  When a request from a client behind the relay
agent arrives, it may be assigned a dynamic IP address from *any* of
the pools listed on that agent's 'gateway' statement (since there's no
way to tell which "pool" the client should draw from -- the client's
request is simply stamped with the relay agent interface's primary IP
address).

If the server's interface is attached to a wire that contains multiple
IP networks, define these the same way.  I.e. in addition to specifying
a 'gateway' statement for the server's interface, use a 'proxy'
statement to define the additional IP networks on that interface's
wire.  And list any dynamic IP address pools in the 'gateway'
statement.

The sample dhcpd.conf file in sample/dhcpd.conf.sample2 has been
updated to show the new feature, as has the dhcpd.conf man page.

---

The code that walked the interfaces, getif() and init_interface_tab()
in getif.c, tended to be the least-portable of the code.  I've replaced
init_interface_tab() with a new version init_interfaces() which is
based on the example given by W. Richard Stevens in "UNIX Network
Programming, Volume 1", Second edition.  I'm hoping this will improve
portability.  

I've also added a note to 'Installation' that changing the
CDEFS in the top-level Makefile can sometimes resolve startup ioctl()
errors.

The interface information is now stored in a linked list instead of a
statically-sized array, so there's no longer a MAX_INTERFACES constant
you'd have to increase on a server with more than 10 interfaces.  I've
revised the other functions in getif.c accordingly.

---

Previous configure script was generated by autoconf 2.1, current one was
generated by autoconf 2.12.

In PU patch 3, code for defining HAVE_STROPTS_H based on the existance
of stropts.h was added to configure and config.h.in, but was never
added to configure.in.  Now it is in configure.in.

In PU patch 3, code for defining CONFIG_SOCKARGLENTYPE based on whether
the type socklen_t was defined was added to configure and config.h.in,
but was never added to configure.in.  If CONFIG_SOCKARGLENTYPE
was not defined, defs.h would typedef socklen_t to an int.
Now the check for the socklen_t type is integrated in configure.in;
if socklen_t is not defined, it is defined (by config.h) as an
unsigned int.

In PU patch 3, code for checking for the existance of libgen
and adding it to LIBS was added to configure, but was never
added to configure.in and config.h.in.  Now that's been integrated.

In PU patch 3, code was added to configure and the Makefiles
to check if the system was UnixWare, and if so, to define XDEFS to -D_KMEMUSER
and to add libresolv to LIBS, to make dhcpcmd and snmpd work.  Now the
check for UnixWare has been integrated into configure.in.  The
-KMEMUSER symbol is now defined accordingly in config.h.in so XDEFS
is no longer needed.

In PU patch 3, code was added to configure and config.h.in to
check if the system was UnixWare, and if so, define the SVR4 symbol.
That symbol was used in getif.c and hwaddr.c to select the use of
stream ioctls intead of BSD ioctls when working with sockets.
Now the decision to use stream ioctls is based instead on a 
more specific USE_STREAM_IOCTLS symbol.  I've added code
to configure.in to define USE_STREAM_IOCTLS when appropriate.
The heuristic it presently uses is to check for the presence
of the stropts.h header.  If it is present, then we check if
the system is on a short list of systems known to require
stream ioctls for sockets (presently that list only includes
UnixWare).  If your system should be added to this list, please
let me know, and define USE_STREAM_IOCTLS manually for now.

New files acconfig.h and aclocal.m4 added in support of autoconf.

---

Previously lease expirations were only logged when the debuglevel was 
4 or greater.  Now you can force them to be logged regardless of the
debuglevel with the new -e option.

---

Mel Lew <melvin at columbia dot edu> points out that if a client specifies 
a DHCP Client ID option with a value different than its hardware address, 
it can cause problems.  

This is because we were being lenient when looking up Client ID's
in the bootptab.  Sometimes when looking for a bootptab entry
matching an incoming packet's Client ID, if we did not find it,
we'd retry the lookup, this time using the incoming packets
htype and haddr.  If we found it on the second try, we'd
consider that a match.  This eventually led to inconsistencies
in the tables recording leases.  

We're no longer lenient; the retry described above no longer happens.
As a result, clients that were specifying garbage DHCP Client ID option
values but receiving service by virtue of the retry will no longer
get service.  And bad bootptab entries that specified garbage
'cl' tag values but still worked by virtue of the retry will also
no longer work.  The bad DHCP client's should be reconfigured (or fixed)
to specify good (or no) DHCP Client ID option, and the bad bootptab
entries should be corrected.

---

If we received a packet which contained a htype (hardware type) code that we've
never heard of, we'd dump core.  Now we ignore the packet, logging a message
at LOG_NOTICE if debuglevel is 3 or higher.

---

mark at sunsite dot unc dot edu (mark at zang dot com) has made a compiled version of
dhcpd with the Princeton patches for Solaris available on Sunsite;
you may want to retrieve that if you have difficulty compiling.
It's presently available as a Solaris package (for 2.5, 2.5.1, and 2.6;
earlier releases may work also) for SPARC hardware.  Visit:

http://sunsite.unc.edu/pub/packages/solaris/sparc
 ftp://sunsite.unc.edu/pub/packages/solaris/sparc

(Look for a filename that starts with 'dhcp' and check to see what
version number (patchlevel) it includes.) 

---

When we receive a DHCPREQUEST from a client in INIT-REBOOT, and the
requested IP address is for a dynamic IP address, we now have an
additional check before granting the request.  We check to see if the
client id appears in the bootptab with a static IP address assigned.
If so, and if that static IP address would be appropriate given the
network to which the client is presently attached, then we NAK the
DHCPREQUEST.

Previously we would ACK the request, so the client continued using the
dynamic IP address it had requested.  That was in keeping with the
spec, but was rarely what you wanted to happen.  If you've changed the
client's entry in bootptab so that it now has a static IP address
appropriate for the network to which it is attached, you normally want
it to be assigned the static IP address in preference to a dynamic IP
address.

By NAKing the request, we force the client from INIT-REBOOT back to
INIT.  Now when the client sends a DHCPDISCOVER, we'll offer the static
IP address.  (And at the same time, if our bindings indicate that the
client id is presently bound to the dynamic address, we'll remove that
binding at the same time, since we know the client is no longer as
we've determined he's in INIT state.)

Note that this change in policy only affects clients in INIT-REBOOT
state.  (I.e. the client has to unload/reload the IP stack to get into
this state; e.g. by rebooting the client computer.)  The policy change
does *not* affect a client in RENEWING (or REBINDING) state.  Those
clients can still renew dynamic addresses presently leased to them,
even if a an static address has become available (due to a change in
bootptab), as per spec.  (Recall that the server generally cannot
determine to what network a RENEWING or REBINDING client is attached;
it is forced to believe that the client's requested IP address is
reasonable for the client's present network.  It is up to the user to
power-down a machine before moving it to another network, to ensure it
begins in the new network in INIT or INIT-REBOOT state.)

---

When processing a DHCPDISCOVER or DHCPREQUEST, when we found a current
binding for this client and decided it was OK to continue to use that
binding, we neglected to check to see if the current binding had
already expired.  Such bindings are still present in our current
binding tables until they are garbage-collected.  In most cases, this
wasn't a problem; we just extended the lease as necessary, which made
the binding good.  But there may have been problems if the current
binding we were continuing to use was in fact just the result of an
OFFER that the client never accepted.  In that case, the "binding" was
never a complete lease, so it may not be safe to just extend it.  It's
possible that is what led to the occassional "Sending DHCPNACK: Lease
wasn't offerred" situation that seemed wrong since the server *had*
just sent an OFFER to the client.

---

When we receive a DHCPREQUEST from a client in INIT-REBOOT, if we
already have a binding for this cliid, but the binding was for an IP
address different than the one the client is now requesting, we thought
there was something wrong with our binding hash tables.  We'd remove
the old binding, log an error, and NAK the client.  Now we recognize
that this just means the client has surrendered the old binding; we
still remove the old binding, but do not log an error nor send a NAK.

We don't respond to the DHCPREQUEST; we let the client timeout and
resend it (or timeout and fall back to INIT); either way when we get
the new request, we'll be able to process it without being distracted
by the old binding which has now been removed.  (That's not entirely in
keeping with the spec, but is simpler than trying to restart processing
of the original packet.)

---

bootptab(5) man page says the tag to specify IP Broadcast Address is
'bc'.  That's a typo; it is 'ba'; fixed.  (Dennis Moreno
<dennis.moreno at safetran dot com>)

---

When DEBUG was defined, hash_Delete() was producing some debug messages
even if the debuglevel was < 16.

---

When sending DHCP replies through a relay agent, we neglected to
convert the destination port (bootps_port) to network byte order.
(Chris Tengi <tengi at cs dot princeton dot edu>, Stephen C. Trier
<trier at odin dot ins dot cwru dot edu>, and Petr Lampa <lampa at fee dot vutbr dot cz>)

---

When sending the Time Offset option to a DHCP client, we neglected to
convert it to network byte order.  (Petr Lampa <lampa at fee dot vutbr dot cz>)

---

ipcmp() now checks if either arg is NULL, to avoid crashing on deref
NULL ptr.  

---

We weren't always checking that malloc() succeeded.

---

Made the compiler happier here and there.

---

Ignore requests from clients that specify an Ethernet broadcast or
multicast address in the chaddr field, or in the DHCP Client ID
option.  If debuglevel > 2, we'll log these.  (Stephen C. Trier
<trier at odin dot ins dot cwru dot edu>)

---

When sending DHCP lease expiration, renew, and rebind times, we were
neglecting to convert them to network-byte order.  (Stephen C. Trier
<trier at odin dot ins dot cwru dot edu> and Petr Lampa <lampa at fee dot vutbr dot cz>)

---

When sending the Boot File Size option in DHCP (but not BootP) replies,
we were neglecting to convert it to network-byte order.  (Petr Lampa
<lampa at fee dot vutbr dot cz>)

---

When checking the 'flags' header field in received DHCP packets, we
were neglecting to convert to host-byte order before performing the
check to see if all must-be-zero bits were zero.  When we believed we
found a MBZ bit set, we cleared it in the reply packet, but that value
too was not being converted correctly.

---

When we sent the Boot File Size option in a DHCP reply packet, we sent
it as a 32-bit value.  It should be a 16-bit value.

---

When we received the Maximum DHCP Message Size option in a DHCP packet,
we neglected to convert it to host-byte order before using it.  (Petr
Lampa <lampa at fee dot vutbr dot cz>)

---

When dumping the current bindings or the internal (parsed) bootptab
database to a file, we neglected to show the value of any NetBios over
TCP/IP Name Servers.  (Petr Lampa <lampa at fee dot vutbr dot cz>)

---

The "Maximum DHCP Lease" tag documented in the bootptab man page ("ml")
was not parsed.  Now we'll parse it.  (Petr Lampa <lampa at fee dot vutbr dot cz>)

At this time, we don't use any "ml" value you specify.  That's because
we don't pay attention to any Lease Time suggested by the client in
DHCPDISCOVER or DHCPREQUEST packets.  (If we did pay attention to the
client's suggestions, "ml" would presumably be used to provide an upper
bound on the lease we grant, possibly with some interaction with the
"dl" tag (if specified).  And we'd probably want to have a lower bound
too.)

The length of the DHCP lease we offer is still the the value of the
"DHCP Lease Time" bootptab tag ("dl") if specified; otherwise it is the
value of the DEFAULT_LEASE definition (6 hours, as distributed).

---

Added -S option, which you may use to disable the "BootP siaddr Local
Optimization" feature.  That feature (which is not new, and continues
to be the default behavior) is now more clearly described in the
dhcpd.8 man page.  (Mel Lew <melvin at columbia dot edu>)

---

Added -C option, which you may use to add some compact log messages when
debugging is enabled.  If you want information about each packet but don't
want to run at debuglevel 2 or higher, you may want to enable these
(Mel Lew <melvin at columbia dot edu>).  Typical messages look like:

Mar 27 12:42:29 dhcpd[11554]: DHCPDISCOVER 00609796E682 [128.59.33.1]: found 128.59.33.11 (test.cc.columbia.edu)
Mar 27 12:42:29 dhcpd[11554]: DHCPDISCOVER 00609796E682 [128.59.33.1]: offer 128.59.33.11 (test.cc.columbia.edu)
Mar 27 12:42:29 dhcpd[11554]: DHCPREQUEST  00609796E682 [128.59.33.1]: request 128.59.33.11
Mar 27 12:42:29 dhcpd[11554]: DHCPREQUEST  00609796E682 [128.59.33.1]: lease 128.59.33.11 (test.cc.columbia.edu) until Fri Mar 27 18:42:29 1998 (21600 seconds)
Mar 27 12:42:29 dhcpd[11554]: DHCPpkterror 0102030405060708090A0B0C0D0E0F10 [128.59.33.1]: bad address length 16 != 6

---

You may now increment the debuglevel by sending the process a SIGABRT
signal (SIGIOT on older systems).  You can reset the debuglevel to 0 by
sending it a SIGSYS signal (if this signal is available on your
system).  Signal calls have been cleaned up for consistency.  (Mel Lew
<melvin at columbia dot edu>)

---

dhcp_opts() and cliid_btoa() failed to limit the scope of the the temp
variable 'i' they used internally; they'd overwrite the value of 'i' in
the calling scope.  (Mel Lew <melvin at columbia dot edu>)

---

The optional 'dhcpcmd' program had the filename /etc/snmpd.private
hardcoded into it.  Now that's a new compile-time definition PRIV_FILE
you may modify by editing the Makefile.  (Mel Lew
<melvin at columbia dot edu>)

---

If your bootptab contained entries for IP addresses that were
marked 'dynamic', but did not happen to fall into any of the
pools defined by 'network' statements in your dhcpd.conf, then
we could crash in dhcp_request() when a client asked for one
of those addresses.  Now we know well enough to ignore the client's
request. (Mel Lew <melvin at columbia dot edu>)

=========================================================================

Princeton Patch 5
November 3, 1997


APPLYING THE PATCH

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patches 1, 2, 3 and 4 already applied.  So if you are starting from
scratch, first get dhcpd 3.3.7 from CMU, then apply Princeton patches
1, 2, 3 and 4 in order; each of the Princeton patches via available at
the URL above.

Before applying patch 5, issue the following command:
   mkdir tools

After applying patch 5, issue the following command:
   chmod 0555 tools/gen-config

If you have any local changes to dhcpd, you'll need to reconcile them
against these patches.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I've only
compiled and tested on SunOS 4.1.4 and Solaris 2.5.1.

---------------------------------------------------------------------

WHAT'S CHANGED

Changes since PU patch 4:

---

Handling of DHCPINFORM packets was wrong.  The responses produced
could have little to do with the request that was sent.  It could
crash if the client was not in the bootptab.  Processing a DHCPINFORM
packet could cause entries in the in-memory bootptab hash tables
to become corrupted.  It leaked memory for each response packet it
sent.

I've started working on the problems in dhcp_inform(), but 
until they're fixed, I've disabled processing of DHCPINFORM
packets.  When we receive DHCPINFORM packets, we'll ignore them,
simply logging them if debuglevel is high enough.

---

Some of the calls to hash_Delete() would cause the hashtables to become
corrupted.  That would eventually lead to attempts to dereference null
pointers, or pointer to outside our memory space.  This could eventually
cause dhcp to die.

We call hash_Delete() to remove an element from a hashtable.  We pass
hash_Delete() a hashcode value, and a pointer to a key which identifies
the element to be deleted.  hash_Delete() walks the hash table bucket
locating all elements that match that key, deleting each one in turn.
The problem was that often the hashcode or the key pointer we passed to
hash_Delete() were actually ELEMENTS of the ACTUAL hash member were
trying to delete.  The deletion of that member worked, but then when
hash_Delete() continued walking the bucket to find any other members of
this hash bucket that matched the key, it was trying to match them to
information which only existed in the hash member that was just
deleted.

Now when calling hash_Delete(), we now pass a *copy* of the hashcode
and key ptr (unless the values we are passing are from somewhere
*other* than the hash member being deleted anyway.

---

Changed umask from 0 to 022 in main.c.  The files we create 
(pidfile, dump files, bindings files) should not be world-writable.

Since these files have already been created by earlier runs of
the daemon, you may wish to protect them by issuing a chmod 0644
for each of them.

---

When dumping a host's record (e.g. to the bindings file), we'll now
print one additional line, labelled "expires_time_t".  This contains the
lease expiration time, the information same as the existing "expires"
line we already print, but as a time_t (int) instead of as a string.

This change is is for the convenience of programs that parse the
bindings file and don't want to have to convert the expiration time
from a string back to a time_t.

If you have a program that parses the bindings dump file and looks for the
existing "expires" line, you should make sure it can distinguish it from 
the new "expires_time_t" line.

---

We now write the pidfile as soon as possible after forking, instead of
waiting for the bootptab and dhcpd.conf to be read.  This is to make it
easier for other processes on your system to see that dhcpd is
running.  

Since you might reasonably start sending USR1 and USR2
signals once you can see the pidfile, but our data is not yet loaded,
we'll now ignore those signals until we're ready to handle them.

---

Corrected a call to snmp_set() in dhcpcmd.c that caused a core
dump on some systems (Donald Matthews <Dmatthews at globeandmail dot ca>)

---

Updated 'Installation' doc to indicate that if you receive
errors on the ioctl() calls in init_interface_tab() at startup on
an AIX system, try recompiling with BSD defined
(Tim Rice, <time at trr dot metro dot NET>).

---

There was a typo in snmpd/Makefile.in.
(Jeff Ross <jeff at wisdom dot bubble dot org>, Chris Tengi <tengi at CS dot Princeton dot EDU>)

---

Jeff Ross <jeff at wisdom dot bubble dot org> has contributed
a script to help you create bootptab and dhcpd.conf files.  
It's in tools/gen-config; see the comments in that file for details.

---

I removed a debugging message I inadvertantly left in init_interface_tab() 
in getif.c.

---

Corrected a declaration in do_opts() to remove a compiler warning.
(Chris Tengi <tengi at CS dot Princeton dot EDU>).

---

When debug >= 12, we log the contents of each lastbinding
as we read it from disk (init_dhcp() in dhcp.c).  However, we did not
correctly log the value of the 'expires' and 'last_touch' time.
We only logged a single time value for both of these; which value
was logged could depend on order of evaluation.  Fixed.
(This only affecting messages in the log, not actual operation.)

---

When dumping bindings, we printed a log message as we started the dump.
Now we also print one as we end the dump.

---

In create_stub(), added sanity check that the host structure we are passed
contains an IP address.

---

main.c, readfile.c, dhcp.c, snmp.c, dynamic.c:

When calling hash_Lookup(), hash_Insert(), hash_Exists(), or
hash_Delete() with hp->iaddr as the key, added some extra parentheses
and a cast to make it easier to see what we're passing.

---

Throughout the code we were often sloppy in dealing with struct in_addr's,
specifying the structure when we really wanted the first (and only) 
element of the structure, the s_addr.  This was sloppy, and has been
corrected in various places:

* whenever copying a struct in_addr

* in data2bind() and bind2data() in perm_utils.c:
when converting a binding from/to the representation used in the
bindings files, the bcopy() of last_ip from/to the new struct lastbind
left out the s_addr element name.

* When calling hash_Lookup(), hash_Insert(), hash_Exists(), or
hash_Delete(), we were sometimes using hp->iaddr as the key
instead of hp->iaddr.s_addr. 

* dhcp.c: init_dhcp(): when recovering binding from disk,
when we compute the hashcode for the struct lastbinding's IP address,
we were leaving out the s_addr element name.

* when initializing my_ip_addr in main.c

* throughout sendreply() in main.c

---

dhcp_discover(), dhcp_request(): when create_lease() returned NULL,
we leaked the IP address and memory that we tried to allocate.
Fixed.  (This would happen only under very rare circumstances.)

---

There are some additional messages logged when you run
with debuglevel > 15 and DEBUG is defined.  It's best
not to compile with DEBUG defined unless you're really
trying to debug the code, for performance reasons.

---

Known Bug:

We have some endian dependancies that are not yet fixed.

Wayne Buttles <buttles at wsb dot champlain dot edu> reports that on his
Linux-based server, the lease value returned to client is wrong
endian.

He reports that even executing the following line:
   insert_ulong_opt(rpkt,&opt,TAG_DHCP_IPLEASE,10)
still causes the WRONG value to be sent on the wire.  

Endian problem confirmed by Jeff Ross <jeff at wisdom dot bubble dot org>.

=========================================================================

Princeton Patch 4
February 7, 1997


APPLYING THE PATCH

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patches 1, 2, and 3 already applied.  So if you are starting from
scratch, first get dhcpd 3.3.7 from CMU, then apply Princeton patches
1, 2 and 3 in order; each of the Princeton patches via available at
the URL above.

If you have any local changes to dhcpd, you'll need to reconcile them
against these patches.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I've only
compiled and tested on SunOS 4.1.4 and Solaris 2.5.1.

---------------------------------------------------------------------

WHAT'S CHANGED

Changes since PU patch 3:

---

The documentation said that a SIGINT caused the server to exit
gracefully, but the server actually just caught the signalled
and continued.  Now we exit gracefully.  

We *also* will now exit gracefully if we get a SIGQUIT.  (And we
continue to do so on a SIGTERM.)

---

On some SVR4 systems, init_interface_tab() (called at startup to
determine each interface's IP address/broadcast address/netmask),
would fail, displaying at ioctl error.  I've fixed this, I hope.

---

Fixed the following bug that caused the current bindings hash tables 
to become incorrect or inconsistent. 

When we processed a DHCPDISCOVER packet, we failed to initialize
cl.clhashcode.  As a result, the current binding's entry in boundhshtbl
was entered using the wrong key (the value of this uninitialized
variable).  This would turn up later when we tried to locate the entry
or remove it; a typical error message was:

dhcp_request(): INIT-REBOOT: ReqIp (140.180.14.9) found in ipboundhshtbl with correct cliid...  
Client id: 01 08 00 07 BD 4F 89  len=7
but cliid *NOT* found in boundhshtbl!
freeing binding

I think it's possible that this error could also have led to later
hash_Insert() errors.

---

In the newest draft of the DHCP spec (draft-ietf-dhc-dhcp-09.txt),
section 4.1 further defines "Server Identifier."  It specifies that
when a client specifies a Server Identifier option, the server must
recognize *any* of the server's own IP addresses as valid.

Previously, we were only recognizing 'my_ip_addr' (essentially, the
server's primary IP address; see dhcpd(8) for details).  Now we'll
recognize any of the IP addresses associated with the server interfaces
(the list we learn by walking the host's interfaces at startup).

(Note that if you reconfigure the server to remove one if its IP
address, DHCP clients current bound to the server may not be able to
renew their leases, if they happen to be bound the Server Identifier
corresponding to the IP address you removed.)

----

For some reason, the use of sigaction(), if available, was disabled;
instead we always used old-style signals for the signals we expected to
return from.  I've re-enabled the use of sigaction() if available for
those signals.  (As a result, you no longer need to (nor should)
manually add the SYSV symbol to CFLAGS in the top-level Makefile.)

---

If you specified the 'bootp' access flag for a dynamic cable range in
the dhcpd.conf file (to restrict these addresses to BootP clients), the
server would still hand out these addresses to DHCP clients.  Fixed
access_network() so this no longer happens.

---

There were problems with the implementation of the "roaming" access
policy.

When attempting to locate a dynamic IP address for a client, the server
didn't properly take into account whether the client had the ":ro:" tag
specified in its bootptab entry.  Fixed.

At startup, when the server read the lastbindings directory to
determine what bindings should be re-instated as current bindings, it
could fail to re-instate those for DHCP clients which were obtained via the
'roaming' access policy.  Fixed.

I've fixed the doc to better describe the roaming feature.

---

At startup, when the server read the lastbindings directory to
determine what bindings should be re-instated as current bindings, it
did not check *current* access policies for dynamic addresses.  Now it
checks those, and will not re-instate a binding if the IP address is no
longer allowed based on the *current* access policies.

---

Added a new tag 'ba' to those understood in a bootptab file.  This lets
you specify an IP broadcast address (option 28).  E.g.
':ba=140.180.192.255:'.

---

If you specified the following tags in bootptab, their values were not
returned to DHCP clients, even when the client specifically requested
them via a Parameter Request List option:  bootsize (bs), dumpfile (df), 
extension file (ef), root path (rp), swap server address (sw), time 
offset (to), and nis domain name (yd).  This is fixed.
---

Most bootptab tags you specified were not inserted into DHCPOFFER and
DHCPACK messages *unless* the client specifically requested them via a
Parameter Request List option.  (The only ones that were always
returned were:  the IP address, bootfile (if specified), tftp server
address (if specified) lease time, renewal time, rebinding time, and
user class (if specified).)

E.g. even if the bootptab entry had a 'ds' (domain name servers) tag,
if a client did not specifically request the domain name servers,
they would not be returned in DHCP replies.

You can now specify the new ":nr:" (Send Non-Requested Options) boolean
tag in the bootptab entry, to cause the server to return *all* bootptab
tags to DHCP clients.  (The tag was previously defined in the code, but 
not documented nor fully implemented.)

Why didn't I simply change the code so the behavior specified by ':nr:'
is the default?  Well, I didn't want to break anyone who may be (unwittingly) 
relying on the old behavior.

Note that if you specify the :nr: tag, we'll still attempt to insert
any options specifically requested by the client in a Parameter Request
List *before* we try to insert any remaining options.

---

If a client specified a Parameter Request List option in a DHCPDISCOVER
packet, the server would ignore that option when constructing the
DHCPOFFER packet.  Fixed.

---

Added new '-x' commandline option to allow you to override the compile-time
default for the config file (normally "/etc/dhcpd.conf"). 

---

Documented a pre-existing bug: if the server finds it must overload the
'file' or 'sname' fields (DHCP Option Overload), any values in those
fields are overwritten, *without* being moved to the new options designed
to hold them.

---

Documented a pre-existing bug: if you specify a presently-unrecognized
bootptab option using the generic (:Txxx:) tag, that option will *not* be
returned to DHCP clients.  (That's true even if the DHCP client
requests it via a Parameter Request list option, or you specify the new
':nr' option.) 

(The option *is* still returned to BootP clients.)

---

If you removed a dynamic IP address from the bootptab (or simply made
it static instead of dynamic) while the IP address was part of a
current binding, then when the server detected the change it would
remove the binding, *but* put the address back in the pool of available 
dynamic addresses.  Fixed so the address is no longer put back in the pool 
of available dynamic addresses.

---

When sending a DHCPOFFER or DHCPACK, the server is permitted to put its
hostname in the sname field.  Previously it left this field alone (was
copied from request packet), except if the field needed to use it for
overflow options.  Now we put the server hostname there (it will still
be overwritten if the field is used for overflow options).

---

If the bootptab entry had a TFTP server address tag (sa) set, we failed
to insert that IP address in the siaddr field in DHCPOFFERs and
DHCPACKs.  (It was included in BOOTPREPLYs.)   This is fixed.

---

Added a new -a commandline option.  Specifying this tells the server to
log address assignments in a form convenient to parse (e.g. to to
create reports).  See the dhcpd man page for details.

---

The boottpab man page claimed that specifying :to: (Time Offset) as a
boolean tag was the same as specifying :to=auto:, but in reality, the server
treated the boolean case as a syntax error.  Now the server behaves as
the man page describes.

---

Documented a pre-existing bug: when sending a DHCP reply, any bytes in
the options field following the END option are supposed to be filled
with PAD options.  We don't do this yet.

---

Previous version of the man page noted that the daemon could be started
by inetd, but recommended starting it from your host's startup
scripts.  That recommendation has been changed to be more emphatic.
The startup overhead is just too high to make inetd a good choice
here.  (I've also stopped testing the daemon to make sure it works
properly when started by inetd.)

---

Added note to Installation document, explaining the 'port already in
use' error message you may see at startup could be because you already
have another process bound to the standard SNMP port (udp 161).

---

Message fixes/enhancements:

When we see a request with some must-be-zero bits *set* in the 'flags'
field, we produced a message if the debuglevel was 3 or higher.  Now
the message is only produced at debuglevel 10 or higher.

When we see a DHCPREQUEST from a client in the INIT-REBOOT state
requesting an IP address inappropriate for client's present subnet, the
message we produce (at debuglevel 2 or higher) has been changed to
mention the Requested IP Address and the Boot Relay Agent IP address.

When we see a DHCPREQUEST from a client in the SELECTING state that
requests an IP address differing from the IP address presently bound
(offerred) to that client, the message we produced (at debuglevel 4 or
higher) didn't correctly print the two IP addresses; now it should.

When we see a DHCPREQUEST from a non-local client in the REBINDING state
requesting an IP address differing from the IP address presently
bound to that client, the message we produced (at debuglevel 4 or
higher) didn't correctly print the two IP addresses; now it should.

A number of error messages that cited the Client Identifier would print it 
on a separate line from the rest of the message, making it difficult to
understand interleaved syslog messages.  The Client Identifier has been moved 
into the body of these message.

Removed repetitious text from some error messages (e.g. "Client is confused!",
"Something is wrong!").

When the client specified an Ethernet chaddr of twelve bytes of zero, or 
the client specified a Client Identifier option of twelve bytes of zero, 
we could produce a few lines of messages.  Now we'll produce just one
line.

=========================================================================

Princeton Patch 3
December 26, 1996 


APPLYING THE PATCH

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patches 1 and 2 already applied.  So if you are starting from
scratch, first get dhcpd 3.3.7 from CMU, then apply Princeton patches
1, 2 and 3 in order; each of the Princeton patches via available at
the URL above.

You may have some local patches you'll need to reconcile against this.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I've only
compiled and tested on SunOS 4.1.4 and Solaris 2.5.1.

---------------------------------------------------------------------


WHAT'S CHANGED

Here are the changes since Princeton patch 2:

---

We could crash in free_client_info() in dhcp.c, due to freeing a
variable that wasn't malloc'd.  (Reported by several people.)  Thanks
to Andreas Steinmetzler <astein at pallas dot de>, Marc Beuchat
<marcb at siana dot neu dot sgi dot com>, and others, for pointing this out.

---

There was a bug in dhcp_request() in dhcp.c.  A client would boot and
be assigned a dynamic IP address.  The client restarted before the
lease expired, and came up in INIT-REBOOT state.  The server still had
the current binding, as it should.  The client specified the same IP
address it had before in the Requested IP Address option.  The server
would incorrectly report that current binding was assigned via BootP
instead of DHCP, and clear it, then assign a fresh one.  (The new
assignment could be the same just-freed dynamic IP address, or another
dynamic one.) Now the server properly recognizes that current binding
was assigned via DHCP and re-uses it.

---

Jeff Ross <jeff at wisdom dot bubble dot org> reported the following error
appearing repeatedly in syslog:  "Tried to assign an ip which already
had a binding (ip address here)".

I found three likely causes for the problem:

     1)  When we got a DHCPDISCOVER and do not find a current
appropriate binding for this client to re-use, we next checked the
client's lastbinding to see if that is appropriate, and if so, re-use
it.  However, we were failing to check if that IP address was already
bound to someone else; now we check that, and if so, do not use that
address.  If the lastbinding was not present or not appropriate, and
the client specified a Requested IP Address option, we check to see if
it is appropriate, and if so, use it.  However, we were failing to
check if that IP address was already bound to someone else; now we
check that, and if so, do not use that address.  (Changed
dhcp_discover() in dhcp.c)

     2) The problem could also be caused by the following bug:
When we got a DHCPREQUEST from a client that is INIT-REBOOT, and the
Requested IP Address is a dynamic IP address, and that address is
appropriate for the client, and is not presently bound, we grant it to
the client.  We were putting it into the ipboundhshtbl, but failing to
remove it from the pool of available dynmamic IP addresses.  (Changed
dhcp_request() in dhcp.c)

     3) The problem could also be caused by misconfiguration:
If the dhcpd.conf file contains 'network' statements in which the IP
addresses ranges overlap, bad things can happen, including this.  Added
code to get_dynamic_ip() in dynamic.c to provide more diagnostics.
Added warning about overlapping 'network' statement IP ranges to the
dhcpd.conf sample file.  (Though we are not specifically checking for
this configuration error; we won't warn in all cases, just those we
notice.)

---

Jeff Ross <jeff at wisdom dot bubble dot org> and Andrew Smith Andrew Smith
<abs4 at york dot ac dot uk> saw "hash_Insert(boundhshtbl) failed! Something's
wrong!", "not increasing 'leases' counter...so count may no longer be
right" messages.  I think most of these were cured with the fixes
above, but not all.

The remaining causes may be associated with the boundhshtbl and
ipboundhshtbl falling out of sync.  (Both reflect the current bindings;
the first is keyed by clientid and the second by ip address.)  It's
possible that this is triggerred by having multiple clients attempting
to use the same clientid.   

I've added some more text to the error messages, to make it clearer
what state we're in when they happen.

I've located a couple places where we were letting the two tables fall
out of sync, and fixed them.

As we always assumed these two tables were in sync, we typically only
looked things up in one of the two tables (whichever was more
convenient given the data we had).  Now we look things up in both
tables, and check that everything agrees.  If we find that things don't
agree, we'll produce more error messages, which may help track down any
remaining bugs in this area.  Although I've added all those tests,
I've not been able to exercise all the paths through the code, as
I've not been able to produce most of the pathological condictions they're
intended to catch.

---

Jay Plett <jay at silence dot princeton dot nj dot us> found that dhcp_inform() was
not putting the user class value into the reply packet correctly, since
it was mistakenly looking at the length of the vendor identifier
value.  Included his fix.

---

Included UnixWare patches from Tim Rice <time at trr dot metro dot NET>:

The INSTALL macro in the top-level Makefile.in is now @INSTALL@ instead
of 'install'.  (Also from ChrisTengi <tengi at CS dot Princeton dot EDU>.)

The CC macro in all Makefile.in files is now @CC@ instead of gcc.
(Also from Chris Tengi <tengi at CS dot Princeton dot EDU>.)

The top-level Makefile has a new 'distclean' target you can use to
remove all the files built by 'configure'.

Added support for socket APIs with "buffer length" size other than
int.  There's a new CONFIG_SOCKARGLENTYPE def which 'configure' will
set to trigger the use of the new socklen_t typedef.

configure now tests for and defines SVR4.

configure now tests for libgen and sets LIBS appropriately.

configure checks for stropts.h and defines a new HAVE_STROPTS_H
accordingly.

configure now checks for UnixWare, and if found, adds -lresolv to
LIBS (needed for strcasecmp), and defines the new XDEFS to be 
-D_KMEMUSER.

The Makefile.in files for dhcpcmd and snmpd now includes XDEFS
when setting DEFS, to get the -D_KMEMUSER.

Added include of net/if.h to a couple places, include of fcntl.h,
stropts.h based on new HAVE_STROPTS_H.

The initialtion of servers[] in dhcpcmd.c is now ' { NULL }' instead of
'{ }'.  (You still need to replace this with your servers if you want
to actually use dhcpcmd.)

Fixed some variable types and added some casts to eliminate compiler
warnings.  Added some new-style function prototypes.

---

Included Chris Tengi's <tengi at CS dot Princeton dot EDU> corrections to
man/bootptab.5 to include various missing tags.

---

Included Chris Tengi's <tengi at CS dot Princeton dot EDU> patch to process_bindata() 
in readfile.c; 'str' was not being initialized.

---

If we have trouble parsing dhcp options, attempt to report the
client identifier or chaddr, if possible.

---

Updated bootptab(5) man page to describe how the $V, $C, and $DHCP
override entries work.  Updated references to RFCs and Internet
Drafts.  Updated to refer to dhcpd, not bootpd.  Moved some
sections around.

---

Some broken or misconfigured clients apparently claim to have the
bogus Ethernet address 0:0:0:0:0:0.   If the bootp/dhcp header
htype==0x01 and chaddr=0x000000000000, we'll log the error and not
try to respond.  Additionally, if a dhcp packet contains a Client ID 
of 0x01000000000000, we'll do the same.  (The latter is not strictly 
illegal, but seeing it should tip you off that the client is broken or 
misconfigured.) Thanks to Jeff Ross <jeff at wisdom dot bubble dot org>.

---

Some error messages indicating problems with the request packets
that should have been produced at debug level 2 or higher were
being produced only at debug level 3 or higher; fixed.

---

Jeff Ross <jeff at wisdom dot bubble dot org> reports that OPT is not passed
from the top-level Makefile to the rest.  Fixed, and also changed
to pass DEBUG as well (instead of leaving it always set to define 
DEBUG in the lower-level makefiles).

---

If any of the "Must Be Zero" bits in the 'flags' field (in the
header) are set, they used to be copied into the reply packet.
We'll now clear them before sending a reply.

---

Created man pages for dhcpd(8) and dhcpd.conf(5).
They're still a bit rough around the edges.

---

In the top-level Makefile.in, I rearranged the definitions for
CHECK_FILE_ACCESS, TAB-FILE,  CONFIG_FILE,  HASHTABLESIZE, and
LASTBINDIR so that local customizations will be easier to see.
Fixed the completely messed-up PID_FILE example definition.

---

Rewrote the 'Installation' document to provide a bit more
detail.

---

Updated sample/dhcpd.conf.sample2 to agree with the man page.

---

Moved README.PRINCETON (the readme file that accompanied Princeton
patch number 1) to README.PRINCETON1, to follow the convention
the other patches are following.  Replaced README.PRINCETON contents 
with generic text explaining what these patches are and where to
obtain them.

=========================================================================

Princeton Patch 2
October 29, 1996


APPLYING THE PATCH

The patch is against dhcpd version 3.3.7 as distributed by CMU, with
Princeton patch version 1 applied.  So if you are starting from
scratch, first get dhcpd 3.3.7 from CMU, then apply Princeton
patch 1 (http://www.princeton.edu/~irwin/src/CMU-dhcpd-3.3.7-PU-patch1.Z),
then apply this patch.

You may have some local patches you'll need to reconcile against this.

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I've only
compiled and tested on SunOS 4.1.4 and Solaris 2.5.1.

---------------------------------------------------------------------

WHAT'S CHANGED

Here are the changes since Princeton patch 1:

We could crash when we got a bootp request if that client currently was
in our table of current bindings, but the IP address had been removed
from the bootptab.  Fixed.

We could crash when we received a DHCPDISCOVER if the client had an
appropriate static IP address listed in bootptab, and was presently
bound via a DHCP assignment. Fixed.

If you have defined pools of dynamic addresses, get_dynamic_ip() could
spent a long time walking through all the free addresses/pools for a
given gateway, every time we considered handing one out.  This makes it
appear the server is stuck for long periods of time.  I sped this up,
moving the time-consuming PING of the candidate address to the end,
after all other possible tests have been done.  Also, instead of
testing each candidate's IP address against the gateway's IP
address/netmask, instead just test a pool's IP address/netmask against
the gateway's, once, before trying to walk a pool.
When dumping bindings, show the binding "code" value, indicating how
the address was assigned.

Added call to create_lease() in dhcp_discover(), as published by
Nancy L Wong <nancy at watsun dot cc dut columbia dot edu> on mailing list.  Removed my
less-correct fix in create_stub() that copied lease time from bootptab
entry into stub.  The result is that info in the bootptab DHCP and VEND
dummy entries are now propagated properly to the client.

When starting up, provide more detail about the bindings we are
reading, assuming debug level is high enough.

Added samples/dhcpd.conf.sample2, another sample dhcpd.conf file.
This one contains more comments that may better illustrate
the use of the various keywords.

Added new feature to let you expire infinite (bootp-assigned) dynamic
addresses; see section below.  As a side effect of this new feature, we
*lose* support for specifying 0xFFFFFFFF (infinity) as a possible lease
time in bootptab.  (I suspect I may have introduced some bugs for the
'roaming' (':ro:') feature, as that's not one I use/test.)

---------------------------------------------------------------------

EXPIRE INFINITE DYNAMICS FEATURE

I added the capability to expire those assignments made via bootp for
dynamic addresses.

BootP assignments must normally be recorded as infinite, as the client
has no way to time out the assignment.  But if you have some external
means to ensure that the BootP clients being assigned dynamic addresses
will timeout their assignments (e.g. power cycle clients periodically),
then you can use the new feature to have the server reclaim those
addresses as well, making them available again for re-assignment.

To turn on this new server feature, specify the new
"expire_infinite_dynamics" keyword in the dhcpd.conf file; it takes a
required argument of a time (in seconds).  The server will reclaim any
infinite (i.e. bootp-assigned) dynamic address after that many
seconds.  (The reclaim will happen during regular dhcp garbage
collection.)

If you set expire_infinite_dynamics to 0, or simply leave it out of the
dhcp.conf file (it is optional), you get the same old default behavior,
which is to never expire these assignments.

Note that we don't provide an expire_infinite_statics, since this
server does not actually record infinite (bootp-assigned) static
assignments in the first place.

=========================================================================

Princeton Patch 1
October 14, 1996


APPLYING THE PATCH

The patch is against dhcpd version 3.3.7 as distributed by CMU.  You
may have some local patches you'll need to reconcile against this.

I've included some of the changes others have suggested on the CMU 
bootpd mailing list, since I was able to test them here.

(I've *not* dealt with the gcc -I issue in the Makefile.  If you've
dealt with that already, you know what to do.  If that issue wasn't
a problem for, then never mind.)

---------------------------------------------------------------------

PLATFORMS

This code is currently in production at Princeton, but has NOT been
tested extensively in all environments.  In particular, I've only
compiled and tested on SunOS 4.1.4 and Solaris 2.5.1.

---------------------------------------------------------------------

SPECS

The specs I've worked from are RFC 951, as updated by RFC 1542, RFC 1534,
draft-ietf-dhc-dhcp-07.txt, and draft-ietf-dhc-options-1533update-04.txt.

---------------------------------------------------------------------

WHAT'S CHANGED


Here's a summary of what I've changed; it is probably not a complete
list, since I'm summarizing things after the fact.

You can redefine what syslog facility messages are logged to.  To do
this, uncomment and edit the LOG_FACILITY definition in the main
Makefile.  (Do in Makefile.in before running 'configure' if you want
this change preserved every time you run 'configure'.)

If we're running standalone, we'll write out the processid to /etc/dhcpd.pid.
You can override the filename by uncommenting and editing the PID_FILE line
in the main Makefile.  (Do this in Makefile.in before running 'configure' if
you want this change preserved every time you run 'configure'.)

I uncommented the call to enable SO_BROADCAST.  (Why was it commented out
for all platforms; on what platforms should it be commented out?)

We used to stay in the foreground (don't fork) if you specified a debug
level greater than or equal to 3.  Now we always go into the
background, except if you specify the new "-f" (Don't Fork) option.
This lets you control your debug level and forking behavior
independantly.

Many changes to debugging and log messages; see section below.

Many changes to the way we decide whether to assign/offer the client an
address, or be silent, or NAK the client.  See the section below.

Added new -u (Renew Unbound Statics) option, to allow multiple servers
handling statically-assigned addresses provide better redundancy.  See
the section below.

Fixed a memory leak, I hope.  

Restored the code that supports the CMU cookie-style bootp
requests/responses.

When sending DHCPACK, the old code could leave out the lease
time.  Ditto for DHCPOFFER.  This is fixed.

When sending DHCPNACK, the old code left out the server identifier
option.  This is fixed.

When sending DHCPNACK, the old code always inserted the clientid
option.  The specs does not seem to require this if the client did not
specify this option.  Including the clientid in this case could
conceivably confuse clients, since they way we infer a clientid for
clients who don't specify it might differ from their idea of their
clientid.  So if the client leaves out the clientid option, we leave it
out of our NACK.

The dump_bootptab and dump_bindings functions (requested with USR1 and
USR2 signals) are now available even if you compile without DEBUG
defined.  (They're too useful to be treated as just code debugging
features.)

The code used to select an IP destination for an outgoing packet has
changed, to more closely follow the specs.  We should put less garbage
in our arp cache, and be able to get NAKs to clients correctly.
Multihomed hosts still will not be able to send a response packet to a
client, if the packet must be broadcast, and the client is attached to
one of the server's non-primary interfaces (see below).

Previously we assumed the server had just one IP address; the first one
returned by 'gethostbyname'.  While we still treat that as "my ip
address" (e.g.  when identifying ourself to clients), at startup we now
walk the OS's interface structures, to determine the IP address and
netmask for each interface.  (Displayed on startup at debug level 4 and
higher.) Although this server *still* is really not designed to work on
a multihomed host (see below), this at least lets us *correctly*
determine whether we need to prime our arp cache before sending a reply
packet.  And we can do a somewhat better job in determining if an
proposed IP address is appropriate for the network to which the client is
attached, when giaddr==0.....though there are still serious problems with
this (see below).

Added more comments to information produced by dump_bindings.  Also
print information about cable and expire values.

Top-level Makefile was missing some header file dependancies.

dhcp_opts() treated the max msg size option as 4 bytes long;
spec says it is 2 bytes long.  Problem was pointed out by
Bob Deblier <bob at pimc dot be> on CMU mailing list.

Include the following changes to the Makefiles, publihsed by 
Mohamed Ellozy <ellozy at netman-mel dot dfci dot harvard dot edu) on CMU mailing list:
add dependancies upon ../config.h to the snmpd, snmplib and dhcpcmd
makefiles;  make clean cleans out subdirectories; changing CC
in top-level Makefile is propagated to lower-level makefiles;
dhcpdcmd added to 'all' target in top-level Makefile.

Included fix to increment of tmpaddr in kw_network(), published
by Petr Lampa <lampa at fee dot vutbr dot cz> and Jeff Licquia <jal at cssroute dot lexdoc dot com>
on the CMU mailing list.

Included fix to uninitialized fromlen variable in ping(), published by
Petr Lampa <lampa at fee dot vutbr dot cz>, and David M.  Meyer
<meyer at network-services dot uoregon dot edu> on the CMU mailing list.

Included fix to include various header files, published by
Petr Lampa <lampa at fee dot vutbr dot cz> on the CMU mailing list.

Include fix to processing of END tag (resetting overload flag),
published by Robert Lee <robert at spin dot net dot uky dot edu> and
Mel Lew <melvin at columbia dot edu> on the CMU mailing list.

Included fix to dhcpdecline() that prevented it from calling dhcp_opts(), 
published by Nancy L Wong <nancy at watsun dot cc dut columbia dot edu>
on the CMU mailing list.

Include printing of 'dy' tag when dumping a host entry,
as pointed out by Petr Lampa <lampa at fee dot vutbr dot cz> on the
CMU mailing list.

Numerous small bugs fixed.  Numerous bugs probably introduced.

---------------------------------------------------------------------

HOW WE SELECT AN ADDRESS TO OFFER/ASSIGN, OR NAK

I had a lot of problems with the way the old code selected
among sending an address to the client, being silent, or
sending a NAK to the client.   Too often I'd find that
it was responding affirmatively to a client that it should
have been ignoring or NAKing, because it didn't perform
all the appropriate tests.  (In a few cases, I found it
NAKed when it should have been silent, too.)

I ended up revising much of the routines that make these
decisions (bootp_request(), dhcp_discover(), and dhcp_request()),
so that they behave much more as the relevant specs say they
should.  Ditto for the support routine check_net(), and a
new routine is_local().

We're also much more particular about the client sending us request
packets that meet the current specs.  That's because we are looking
more closely at some of the fields to determine in what state the
client is in.  We need to do this because the spec often proscribes
different server behavior based upon the client's state.  (This is
especially true for the much-overloaded DHCPREQUEST packet.)  So if you
have clients that produce request packets that don't meet the current
spec, you could have some problems with this new code.

The upshot is that you are likely to see different behavior from the
server here.  For example, we're smarter about dealing with clients who
move among networks, or who ask to use someone else's IP address, etc.
If you don't understand why the server is assigning (or not assigning)
something here, the best thing to do is to push your debug level up to
7.  Or read the comments in the source for those functions.  The code
isn't as pithy and fast as it was before, but it should be clearer what
we're doing.

I could not always get the server to behave perfectly in accordance
with the specs, because sometimes that would require information not
always available to me via the standard sockets interface on all
platforms.  (E.g. the interface on which a packet arrived, the IP
destination address of a packet.) In those cases, I chose to make the
server behave conservatively (e.g. be silent instead of NAKing).
Comments in the code describe what's going on.

---------------------------------------------------------------------

RENEW UNBOUND STATICS OPTION

I added a -u option that will be of interest if all of the following is
trye for you: you are doing DHCP, you are assigning (some or all) addresses 
statically, and you have multiple servers.

The spec says that when a client goes to renew, it unicasts the
DHCPREQUEST to the server to which it was bound.  If it gets no answer
to its retries after some time, it goes into REBINDING state, and
broadcasts the renewal request, retrying until the lease expires.

When we receive a DHCPREQUEST from a client in RENEWING (or REBINDING)
state, we normally only grant the renewal if the client has an
unexpired lease with us.  Otherwise we ignore the request (unless we're
SURE the address the client is asking for is inappropriate), since the
server the client is bound to should answer.

Now, if we had a server-to-server protocol in place today, our multiple
servers could exchange lease information.  Then when a client went into
REBINDING, any server that has received the lease info could respond to
the client.  But we don't have a standard server-to-server protocol
today.

As a temporary measure, the -u option will let your multiple servers
provide redundant service in this case, *if* the IP address in question
is one that is statically-assigned to the client that's asking.  So if
you have multiple servers all with the same set of static assignments
in their bootptabs, specifying "-u" on all of them will let them
provide redundant service when clients go into REBINDING because their
original server is unavailable.

If the requested IP address is one that is dynamically- assigned, the
"-u" option has no effect.  The server will not provide redundant
service if it sees the requested IP address is listed in the bootptab
as dynamically-assigned.  (That's because in the absence of a
server-to-server protocol, I assume that you must give each of your
servers independent ranges of dynamic IP addresses.)

By the way, this "-u" option has another use, even if you don't have
multiple servers.  Say you have clients who have unexpired leases, but
your server doesn't know about their unexpired leases.  (That would
happen after you convert from another dhcp server product to this one,
or you erase the bindings directory contents because it is corrupted.)
Starting your server with "-u" will help deal with the problem, since
when the clients with leases try to renew, you'll be able to answer
them, even though you didn't have them in your list of unexpired
leases.  Of course, this still only works if we're dealing with
statically-assigned IP addresses, not dynamically-assigned ones.

---------------------------------------------------------------------

LOG MESSAGES AND DEBUGGING

More debugging messages are available, and most existing ones have
changed.

The syslog levels at which we log messages has also changed.  Our rule
of thumb is that LOG_ERR indicates serious problems with the server
itself, or its databases.  LOG_WARNING and LOG_NOTICE indicate
conditions that are quite unusual and you may want to look into.  Most
messages are LOG_INFO level, and show the server in action.  Messages
at LOG_DEBUG are really intended to debug any problems in how the
server maintains its data structures.

We also support a wider range of debug levels.  We produce increasingly
detailed messages as the debug level increases to 16.  Here's a rough
idea of what messages are added at each level:

0: server errors, operational problems, database corruption

1: major events affecting server's operation (i.e. rereading
   databases)

2: arrival of request packet, IPsrc, length, the packet type, 
   the clientid or hardware address, and what IP address we 
   assigned/offerred (only if we decided to do so)

3: adds just a few messages indicating problems with the 
   request packet (short packets, can't decode)

4: adds most of the info about what state the client must
   be in (except a few repetitive ones), and most of the
   steps/decisions the server makes to decide what IP address
   to assign/offer, or why it ignores or NAKs the client.
   also reports interface info at startup.

5: adds just a few messages about the state the client must
   be in that tend to be wordy and repetitive

6: no additional messages

7: adds just a few messages indicating when we are searching
   for an address to assign/offer, and appropriate-network
   checks.  Also adds messages showing how we determine the
   IPdst of response packets

8: no additional messages

9: no additional messages

10: shows the contens of some less-interesting fields in the packet
    (e.g. bootfile, vendor magic cookie).  For DHCP, prints the
    lease expire, rebind, renew times.  Tell you about bootp requests 
    with vend fields shorter than legal minimum.

11: show start and completion of dhcp garbage collection, and
    flush lastbindings to disk

12: when reading bindings from disk at startup, details each
    record read and whether it was added to current bindings.
    Also during DHCP garbage collection, details what's
    done with each binding.  When re-reading conf file or bootptab,
    details which bindings are being removed.

13: Shows bootptab lastmod time every time packet is received.
    When sending packets, shows max length of packet and number
    of bytes left.

14: no additional messages

15: no additional messages

16: all remaining low-level debug messages, typically involving
    maintenance of the data structures.  To get these messages,
    you will also need to uncomment the DEBUG in the top-level
    Makefile.  


Note that the DEBUG definition in the Makefile now only controls the
availability of the level 16 messages.  (The choice between compiling
with the -g or -O option has been moved to a new OPT definition in the
top-level Makefile.)

These changes will provide you with greater ability to decide what
should get logged, and where, and to understand what the server is
doing and why.

If you're not having any problems, but just want to understand the
decisions the server is making, try running at debug level 7.  Unless
you have lots of free space or few clients, you normally won't want to
run with debug higher than 2.

---------------------------------------------------------------------

MULTIHOMED HOSTS

I recommend against running this server on a multihomed host.  There
are two major issues here:

a) Often the server needs to send a reply to the broadcast IP address.
On a multihomed host, which interface this packet goes out is not
well-defined.  This is (deliberately) left unspecified in the current
Host Requirements RFC.  Perhaps the OS copies it to all interfaces; on
many hosts, it goes out the first interface that was configured.  In
the latter case, if the client is attached to a different interface,
then the broadcasted response won't reach the client.

I considered the following workaround: for a multihomed host, replace
each outgoing broadcast packet with a series of subnet-directed
broadcasts, to force one out of each interface.  While that would get
the packets out all the interfaces, I didn't pursue that because then
the reply packets would contain destination IP addresses other than
255.255.255.255 -- which means that according to the BootP and DHCP
specs, they would not be valid BootP and DHCP replies.  Presumably many
clients would not recognize them as broadcasts (remember that these
clients may not know the subnet mask yet).

b) The spec says the server should, in most circumstances, check that
the IP address it is about to hand to a client is appropriate for the
network to which the client is attached.  If the request packet was
broadcast from a non-local network, we determine to what network the
client is presently attached by inspecting giaddr.  

But giaddr will *not* be set if the client is attached to a local
network, or if the request packet was unicast by the client.  When
giaddr is not set, the server *used* to assume the request packet
arrived on the server interface corresponding to the first IP address
returned by 'gethostbyname' on the server.  If the client was actually
on a different local network, this meant the server was making
decisions based on an incorrect notion of the network the client was
presently attached to.  This led to errors in dyanamic IP assignments.
(It didn't lead to errors in static IP assignments, since the server
wasn't checking those before handing them out.  But my mods check
before handing out static assignments as well, as per spec, so these
would be affected as well.)

If we could determine on what interface a request packet arrives, we
could deal with this.  I don't see a portable way to do that while
still using datagram sockets.  (I think one can partially solve the
problem by opening up a datagram socket bound to each interface's IP
address, instead of one bound to INADDR_ANY.  But you also have to
listen for broadcasts, so I don't see how to discover on what interface
those arrived.)

So since we don't know on what interface the packet arrived, the *new*
code checks the proposed IP address against *all* of the networks to
which the server is attached; if the IP address is appropriate for
*any* of those networks, we say that the address is OK.  (We determine
the list of server-attached networks by walking the OS's interface list
and grabbing IP addresses and netmasks.)

That's why I recommend not running the server on a multihomed host.  If
you must, then you can still avoid any problems by making sure there
are NO bootp or dhcp clients on any of the networks directly attached
to any of the server's interfaces.  (If there are no such clients, it
won't be forced to make the bad decisions.) If you must have clients on
those networks, then at least be sure that you're not assigning any
dynamic IP addresses on these networks.


---------------------------------------------------------------------

KNOWN BUGS

If you are building on a machine that needs 'signal()' called
after handling a signal, add "-DSYSV" to the CFLAGS in the Makefile.
(E.g. Solaris 2.5.1)  (Do in Makefile.in before running 'configure'
if you want this change preserved every time you run 'configure'.)
As pointed out by Petr Lampa <lampa at fee dot vutbr dot cz> on the CMU mailing
list, the configure program fails to do this.

When a client successfully renews a lease, much of the information we
provide in the ACK is copied from the current lease.  This is a problem
if any of those values have changed.  (E.g. you fiddle with lease
values in the bootptab, or router list, subnet mask, etc.)  To get the
new values to the client, the existing lease must go away -- e.g. by
expiring, the client releasing it, or the server deciding to remove it
with extreme prejudice.   Note that major changes that invalidate the
client's lease (e.g. removal of client from bootptab, if limiting
service to "registered" clients) will cause the server to remove the
unexpired lease, so that's one way around it.  Sort of.

If you change any of the DHCP lease time values (lease time, rebinding
time, or renewal time in bootptab; or DEFAULT_LEASE definition), these
new values will NOT be provided to clients if they renew unexpired
leases.  When an unexpired lease is renewed, the expire/renew/rebind
time values for the extended lease are just copied from the old lease.
If the client's lease expires (or is otherwise discarded), the next
lease the client is granted will reflect the new values.

Should we really be adding a route to 255.255.255.255 on all OS's?

I wouldn't be surprised to hear that there are still more memory leaks,
or (worse) that we're discarding some information we still need.
(Watch out for bad pointer derefs.)

Don't specify lease times in the optional $DHCP or $Vxxxx bootptab
entries.  We're not looking in those templates correctly for lease time
information.

You may find the new code runs slower than the old code.  I found that
when they old code received a request packet, it often assigned an IP
address without performing many of the tests that were in the spec.
Adding those tests almost certainly slowed things down.  My top
priority has been to get the code to answer correctly, so I've not
spent time optimizing.  There's also some similar code scattered
through bootp_request(), dhcp_request(), and dhcp_discover() that I
have not factored out, because there are enough differences that
parameterizing them would have made it less readable while I was
debugging.

There are a variety of platform-specific include file fixes reported
on the CMU mailing list, but I didn't include them since I wasn't able
to test them.  Ditto for some linux-specific fixes.

As mentioned earlier, I haven't dealt with the -I issue in the top-level
Makefile.

---------------------------------------------------------------------
