RELEASE NOTES July 5 2017 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 12 July 5 2017 UPDATING FROM PATCHLEVEL 11 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, 10, and 11 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-patch12 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 were once in Makefile.in moved in the past 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 were once in 'Makefile' files moved in the past 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 install the new dhcpd.8, bootptab.5, dhcpd.conf.5, and dhcp-bindings-tool.8 man pages manually. 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. --------------------------------------------------------------------- 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 11: ***IRWIN: SEE NOTE AT END** -- We were performing an extra level of backslash interpretation, apparently unintentionally. The code's comments indicate that the intent was that you may enter a literal backslash into a bootptab tag by escaping the backslash; for example: foo: .... :bf=foo\\bar.txt: But the extra level of backslash interpretation were causing both backslashes above to be removed, resulting in the server actually storing the value 'foobar.txt'. To store the value 'foo\bar.txt', you had to enter: foo: .... :bf=foo\\\\bar.txt: We have removed one level of backslash interpretation, so now you should enter the data as was originally intended, that is, as: foo: .... :bf=foo\\bar.txt: -- Support has been added for the WPAD option (option 252). The tag for this option is 'wp'. Although the specification for the WPAD option is that the value is a string, in practice it is common to include a NUL byte at the end. In support of the need to specify arbi trary binary values in this tag, we require you specify the wp tag as a hexadecimal string. For example, to specify the value http://192.168.0.1/foo followed by a newline and a NUL byte, specify the following in bootptab: wp=0x687474703a2f2f3139322e3136382e302e312f666f6f0a00 If you erroneously specify the wp tag as a string, we make no guarantees as to how the server will treat this value. -- Modified some existing log messages generated by processing DHCPREQUEST packets. These are some of the messages produced when the DHCP client is requesting something that doesn't make sense, for example, to renew a lease that has already expired. While the Client Identifier does already appear in the log (in an earlier message generated as we began parsing the request packet), we now also include the Client Identifier in the text of the log message reporting the unexpected condition. This is to make it easier to spot these when searching the log file for a Client Identifier. -- Modified the human-readable message sent in most DHCPNAK packets, to add the requested IP address. Reworded some of these messages. Because at some debuglevels, the human-readable message included in a DHCPNAK is logged while the server's own associated debug messages for the transaction are suppressed, this change can make it easier to understand (in such logs) what has transpired. In such cases, it also make it possible to spot these when searching the log file an IP address. -- Modified the handling for DHCPREQUEST when the client is in the INIT-REBOOT state. When the server already has an unexpired lease on IP address 'A' for this client, and the client requests a lease on a different IP address 'B', and IP address 'B' is one that is available and permitted for this client to lease, and the requested IP address is a dynamic (not static) IP address AND both the existing and dynamic IP addresses are appropriate for use on the network to which the client is presently attached, the server used to assume the client had abandoned the lease on IP address 'A'. The server would discard the binding on IP address 'A', and grant a new lease on IP address 'B'. This was a problem when the client is one that is broken in such a way that it is running multiple simultaneous DHCP client instances on the same interface with the same Client ID. In such cases (which seems to be the ones that get into this situation in the first place), the client continues using both IP addresses 'A' and 'B'. But the server has discarded the binding on IP address 'A'. The server's behavior has been changed. Now it will DHCPNAK the request for IP address 'B'. It will retain the binding for IP address 'A'. Note if IP address 'B' is a static IP address, the server still retains the old behavior. Retaining the old behavior in this case can lead to the problem described above. Despite that, we retain the old behavior because NAK'ing the client in this situation could interfere with the ability of a client to migrate from a dynamically-assigned IP address 'A' to a statically-assigned IP address 'B' when there are multiple DHCP servers. That is, the client may have obtained dynamically-assigned IP address 'A' from our server, then (due to a bootptab change) obtain a lease on statically-assigned IP address 'B' from another server. If the client enters INIT-REBOOT for lease B prior to lease A expiring, and our server were to DHCPNAK the client's request, that DHCPNAK could prevent the client from obtaining a lease on 'B' from another server. It makes sense to allow the client to obtain a lease on 'B' from another server, as our philosophy has always been to prefer that a client obtain a lease on a statically-assigned IP address rather than a dynamically-assigned IP address, when an appropriate statically-assigned IP address is available for the client. -- The log message dhcp_inform() not implemented, ignoring previously produced at debug levels > 1 is instead produced at debug levels > 3. -- Previously we intialized a socket for ICMP each time we needed to ping an IP address. Any error doing so was a soft failure causing us to skip PING. Now we initialize the socket once at daemon start time, and any error doing so as a hard failure. -- You may now tune the parameters dhcpd uses when it pings an dynamically-assigned IP address before sending a DHCPOFFER containing that IP address. There are new configuration file statements: # Before sending a DHCPOFFER containing a dynamically-allocated IP address, # how many times should we ping the IP address to verify it is not in-use? # Any response terminates the timeout and cancels any further tries. # Specifying 0 disables the ping attempt. # Default is 3. ping_offer_dynamic_tries 2 # When we perform each ping try specified by ping_off_dyn_tries, how long should we wait (at most) for a response # to each ping request? # Not used when ping_offer_dynamic_tries is 0. # Timeout is sum of ping_off_dyn_timeout_secs (seconds) + ping_off_dyn_timeout_us (microseconds). # Default is 0 seconds + 500000 microseconds (= 0.5 seconds). ping_offer_dynamic_timeout_secs 0 ping_offer_dynamic_timeout_us 400000 The default values (3 tries, 0.5 second timeout for each try) remain the same as in the past. -- The two-line message: ping says address is already in use: 192.168.10.11 ...will not try to assign this address was consolidated to: ping found IP address 192.168.10.11 in use; will not assign it -- When we receive a DHCPREQUEST from a client in SELECTING state specifying *our* Server Identifier, and the IP address requested by the client is not one we have offered to the client, and we have a binding for this client to a different IP address, we used to NAK the client and discard the existing binding we had for the client. We discarded the existing binding because the client has apparently abandoned the old binding; a client can't both be BOUND and SELECTING on the same network. But there are a number of badly broken DHCP client implementations which do exactly that, sending erroneous DHCPREQUEST in SELECTING state messages (for IP addresses which have expired, for example) at the same time these clients are also in BOUND, RENEWING, REBINDING, INIT, INIT-REBOOT and SELECTING states. Regardless of how we respond to these bogus SELECTING messages, these clients often continue to use the IP address they are presently bound to. So discarding the existing binding for these clients results in additional problems. We no longer discard the existing binding for those clients. We NAK the erroneous DHCPREQUEST in SELECTING state, but retain the existing binding. Upgraded from autoconf 2.65 to 2.69. Replaced install-sh version 2009-04-28.21 from automake 1.11.1 with version 2013-12-25.23 from automake 1.15. Replaced config.guess version 2009-11-20 from automake 1.11.1 with version 2014-11-04 from automake 1.15. Replaced config.sub version 2009-11-20 from automake 1.11.1 with version 2014-12-03 from automake 1.15. Replaced missing version 2009-04-28.21 from automake 1.11.1 with version 2013-10-28.13 from automake 1.15. ========================================================================= 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 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 . 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

.) --- 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 ) --- As suggested by Bruce Hudson , 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 ) --- 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 ) --- Updated TODO to reflect that we fail to compile on some IRIX platforms (reported by Kit-pui Wong ). This is due to a portability bug we have in handling rtentry. Updated INSTALL to provide a workaround. Similar problem reported by Howard Harvey

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

) --- 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

) --- Our reclaration of sys_errlist in several places caused an error on NetBSD 1.3.2. (Howard Harvey

) 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

) --- 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 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 , 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 . (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 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 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 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 , Bob Beck and Jim Campbell .) --- Howard Harvey

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 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 . 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 ) --- 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 ) --- 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 . 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 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 ) --- 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 , Stephen C. Trier , and Petr Lampa ) --- When sending the Time Offset option to a DHCP client, we neglected to convert it to network byte order. (Petr Lampa ) --- 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 ) --- When sending DHCP lease expiration, renew, and rebind times, we were neglecting to convert them to network-byte order. (Stephen C. Trier and Petr Lampa ) --- 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 ) --- 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 ) --- 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 ) --- The "Maximum DHCP Lease" tag documented in the bootptab man page ("ml") was not parsed. Now we'll parse it. (Petr Lampa ) 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 ) --- 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 ). 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 ) --- 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 ) --- 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 ) --- 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 ) ========================================================================= 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 ) --- 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,