README for Princeton Patch 11 April 6 2010 irwin at princeton dot edu This file accompanies Princeton Patch 11 to CMU-dhcpd 3.3.7; it describes how to apply the patch, and what has changed. After you have applied the patch, you no longer need this file, since the information in it also appears in the RELEASE_NOTES file which results from applying the patch. This patch (as well as the complete pre-patched current distribution) is available via: http://www.net.princeton.edu/software/dhcpd/ ========================================================================= 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. ---