README for Princeton Patch 8 October 20, 1999 irwin@princeton.edu This file accompanies Princeton Patch 8 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.princeton.edu/~irwin/dhcpd.html ========================================================================= 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."