RELEASE NOTES May 15, 2002 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 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 succesfully 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@sunsite.unc.edu (mark@zang.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@sunsite.unc.edu (mark@zang.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, ). --- There was a typo in snmpd/Makefile.in. (Jeff Ross , Chris Tengi ) --- Jeff Ross has contributed a script to help you create bootptab and dhcpd.conf files. It's in tools/gen-config; see the comments in that file for details. --- I removed a debugging message I inadvertantly left in init_interface_tab() in getif.c. --- Corrected a declaration in do_opts() to remove a compiler warning. (Chris Tengi ). --- When debug >= 12, we log the contents of each lastbinding as we read it from disk (init_dhcp() in dhcp.c). However, we did not correctly log the value of the 'expires' and 'last_touch' time. We only logged a single time value for both of these; which value was logged could depend on order of evaluation. Fixed. (This only affecting messages in the log, not actual operation.) --- When dumping bindings, we printed a log message as we started the dump. Now we also print one as we end the dump. --- In create_stub(), added sanity check that the host structure we are passed contains an IP address. --- main.c, readfile.c, dhcp.c, snmp.c, dynamic.c: When calling hash_Lookup(), hash_Insert(), hash_Exists(), or hash_Delete() with hp->iaddr as the key, added some extra parentheses and a cast to make it easier to see what we're passing. --- Throughout the code we were often sloppy in dealing with struct in_addr's, specifying the structure when we really wanted the first (and only) element of the structure, the s_addr. This was sloppy, and has been corrected in various places: * whenever copying a struct in_addr * in data2bind() and bind2data() in perm_utils.c: when converting a binding from/to the representation used in the bindings files, the bcopy() of last_ip from/to the new struct lastbind left out the s_addr element name. * When calling hash_Lookup(), hash_Insert(), hash_Exists(), or hash_Delete(), we were sometimes using hp->iaddr as the key instead of hp->iaddr.s_addr. * dhcp.c: init_dhcp(): when recovering binding from disk, when we compute the hashcode for the struct lastbinding's IP address, we were leaving out the s_addr element name. * when initializing my_ip_addr in main.c * throughout sendreply() in main.c --- dhcp_discover(), dhcp_request(): when create_lease() returned NULL, we leaked the IP address and memory that we tried to allocate. Fixed. (This would happen only under very rare circumstances.) --- There are some additional messages logged when you run with debuglevel > 15 and DEBUG is defined. It's best not to compile with DEBUG defined unless you're really trying to debug the code, for performance reasons. --- Known Bug: We have some endian dependancies that are not yet fixed. Wayne Buttles reports that on his Linux-based server, the lease value returned to client is wrong endian. He reports that even executing the following line: insert_ulong_opt(rpkt,&opt,TAG_DHCP_IPLEASE,10) still causes the WRONG value to be sent on the wire. Endian problem confirmed by Jeff Ross . ========================================================================= Princeton Patch 4 February 7, 1997 APPLYING THE PATCH The patch is against dhcpd version 3.3.7 as distributed by CMU, with Princeton patches 1, 2, and 3 already applied. So if you are starting from scratch, first get dhcpd 3.3.7 from CMU, then apply Princeton patches 1, 2 and 3 in order; each of the Princeton patches via available at the URL above. If you have any local changes to dhcpd, you'll need to reconcile them against these patches. --------------------------------------------------------------------- PLATFORMS This code is currently in production at Princeton, but has NOT been tested extensively in all environments. In particular, I've only compiled and tested on SunOS 4.1.4 and Solaris 2.5.1. --------------------------------------------------------------------- WHAT'S CHANGED Changes since PU patch 3: --- The documentation said that a SIGINT caused the server to exit gracefully, but the server actually just caught the signalled and continued. Now we exit gracefully. We *also* will now exit gracefully if we get a SIGQUIT. (And we continue to do so on a SIGTERM.) --- On some SVR4 systems, init_interface_tab() (called at startup to determine each interface's IP address/broadcast address/netmask), would fail, displaying at ioctl error. I've fixed this, I hope. --- Fixed the following bug that caused the current bindings hash tables to become incorrect or inconsistent. When we processed a DHCPDISCOVER packet, we failed to initialize cl.clhashcode. As a result, the current binding's entry in boundhshtbl was entered using the wrong key (the value of this uninitialized variable). This would turn up later when we tried to locate the entry or remove it; a typical error message was: dhcp_request(): INIT-REBOOT: ReqIp (140.180.14.9) found in ipboundhshtbl with correct cliid... Client id: 01 08 00 07 BD 4F 89 len=7 but cliid *NOT* found in boundhshtbl! freeing binding I think it's possible that this error could also have led to later hash_Insert() errors. --- In the newest draft of the DHCP spec (draft-ietf-dhc-dhcp-09.txt), section 4.1 further defines "Server Identifier." It specifies that when a client specifies a Server Identifier option, the server must recognize *any* of the server's own IP addresses as valid. Previously, we were only recognizing 'my_ip_addr' (essentially, the server's primary IP address; see dhcpd(8) for details). Now we'll recognize any of the IP addresses associated with the server interfaces (the list we learn by walking the host's interfaces at startup). (Note that if you reconfigure the server to remove one if its IP address, DHCP clients current bound to the server may not be able to renew their leases, if they happen to be bound the Server Identifier corresponding to the IP address you removed.) ---- For some reason, the use of sigaction(), if available, was disabled; instead we always used old-style signals for the signals we expected to return from. I've re-enabled the use of sigaction() if available for those signals. (As a result, you no longer need to (nor should) manually add the SYSV symbol to CFLAGS in the top-level Makefile.) --- If you specified the 'bootp' access flag for a dynamic cable range in the dhcpd.conf file (to restrict these addresses to BootP clients), the server would still hand out these addresses to DHCP clients. Fixed access_network() so this no longer happens. --- There were problems with the implementation of the "roaming" access policy. When attempting to locate a dynamic IP address for a client, the server didn't properly take into account whether the client had the ":ro:" tag specified in its bootptab entry. Fixed. At startup, when the server read the lastbindings directory to determine what bindings should be re-instated as current bindings, it could fail to re-instate those for DHCP clients which were obtained via the 'roaming' access policy. Fixed. I've fixed the doc to better describe the roaming feature. --- At startup, when the server read the lastbindings directory to determine what bindings should be re-instated as current bindings, it did not check *current* access policies for dynamic addresses. Now it checks those, and will not re-instate a binding if the IP address is no longer allowed based on the *current* access policies. --- Added a new tag 'ba' to those understood in a bootptab file. This lets you specify an IP broadcast address (option 28). E.g. ':ba=140.180.192.255:'. --- If you specified the following tags in bootptab, their values were not returned to DHCP clients, even when the client specifically requested them via a Parameter Request List option: bootsize (bs), dumpfile (df), extension file (ef), root path (rp), swap server address (sw), time offset (to), and nis domain name (yd). This is fixed. --- Most bootptab tags you specified were not inserted into DHCPOFFER and DHCPACK messages *unless* the client specifically requested them via a Parameter Request List option. (The only ones that were always returned were: the IP address, bootfile (if specified), tftp server address (if specified) lease time, renewal time, rebinding time, and user class (if specified).) E.g. even if the bootptab entry had a 'ds' (domain name servers) tag, if a client did not specifically request the domain name servers, they would not be returned in DHCP replies. You can now specify the new ":nr:" (Send Non-Requested Options) boolean tag in the bootptab entry, to cause the server to return *all* bootptab tags to DHCP clients. (The tag was previously defined in the code, but not documented nor fully implemented.) Why didn't I simply change the code so the behavior specified by ':nr:' is the default? Well, I didn't want to break anyone who may be (unwittingly) relying on the old behavior. Note that if you specify the :nr: tag, we'll still attempt to insert any options specifically requested by the client in a Parameter Request List *before* we try to insert any remaining options. --- If a client specified a Parameter Request List option in a DHCPDISCOVER packet, the server would ignore that option when constructing the DHCPOFFER packet. Fixed. --- Added new '-x' commandline option to allow you to override the compile-time default for the config file (normally "/etc/dhcpd.conf"). --- Documented a pre-existing bug: if the server finds it must overload the 'file' or 'sname' fields (DHCP Option Overload), any values in those fields are overwritten, *without* being moved to the new options designed to hold them. --- Documented a pre-existing bug: if you specify a presently-unrecognized bootptab option using the generic (:Txxx:) tag, that option will *not* be returned to DHCP clients. (That's true even if the DHCP client requests it via a Parameter Request list option, or you specify the new ':nr' option.) (The option *is* still returned to BootP clients.) --- If you removed a dynamic IP address from the bootptab (or simply made it static instead of dynamic) while the IP address was part of a current binding, then when the server detected the change it would remove the binding, *but* put the address back in the pool of available dynamic addresses. Fixed so the address is no longer put back in the pool of available dynamic addresses. --- When sending a DHCPOFFER or DHCPACK, the server is permitted to put its hostname in the sname field. Previously it left this field alone (was copied from request packet), except if the field needed to use it for overflow options. Now we put the server hostname there (it will still be overwritten if the field is used for overflow options). --- If the bootptab entry had a TFTP server address tag (sa) set, we failed to insert that IP address in the siaddr field in DHCPOFFERs and DHCPACKs. (It was included in BOOTPREPLYs.) This is fixed. --- Added a new -a commandline option. Specifying this tells the server to log address assignments in a form convenient to parse (e.g. to to create reports). See the dhcpd man page for details. --- The boottpab man page claimed that specifying :to: (Time Offset) as a boolean tag was the same as specifying :to=auto:, but in reality, the server treated the boolean case as a syntax error. Now the server behaves as the man page describes. --- Documented a pre-existing bug: when sending a DHCP reply, any bytes in the options field following the END option are supposed to be filled with PAD options. We don't do this yet. --- Previous version of the man page noted that the daemon could be started by inetd, but recommended starting it from your host's startup scripts. That recommendation has been changed to be more emphatic. The startup overhead is just too high to make inetd a good choice here. (I've also stopped testing the daemon to make sure it works properly when started by inetd.) --- Added note to Installation document, explaining the 'port already in use' error message you may see at startup could be because you already have another process bound to the standard SNMP port (udp 161). --- Message fixes/enhancements: When we see a request with some must-be-zero bits *set* in the 'flags' field, we produced a message if the debuglevel was 3 or higher. Now the message is only produced at debuglevel 10 or higher. When we see a DHCPREQUEST from a client in the INIT-REBOOT state requesting an IP address inappropriate for client's present subnet, the message we produce (at debuglevel 2 or higher) has been changed to mention the Requested IP Address and the Boot Relay Agent IP address. When we see a DHCPREQUEST from a client in the SELECTING state that requests an IP address differing from the IP address presently bound (offerred) to that client, the message we produced (at debuglevel 4 or higher) didn't correctly print the two IP addresses; now it should. When we see a DHCPREQUEST from a non-local client in the REBINDING state requesting an IP address differing from the IP address presently bound to that client, the message we produced (at debuglevel 4 or higher) didn't correctly print the two IP addresses; now it should. A number of error messages that cited the Client Identifier would print it on a separate line from the rest of the message, making it difficult to understand interleaved syslog messages. The Client Identifier has been moved into the body of these message. Removed repetitious text from some error messages (e.g. "Client is confused!", "Something is wrong!"). When the client specified an Ethernet chaddr of twelve bytes of zero, or the client specified a Client Identifier option of twelve bytes of zero, we could produce a few lines of messages. Now we'll produce just one line. ========================================================================= Princeton Patch 3 December 26, 1996 APPLYING THE PATCH The patch is against dhcpd version 3.3.7 as distributed by CMU, with Princeton patches 1 and 2 already applied. So if you are starting from scratch, first get dhcpd 3.3.7 from CMU, then apply Princeton patches 1, 2 and 3 in order; each of the Princeton patches via available at the URL above. You may have some local patches you'll need to reconcile against this. --------------------------------------------------------------------- PLATFORMS This code is currently in production at Princeton, but has NOT been tested extensively in all environments. In particular, I've only compiled and tested on SunOS 4.1.4 and Solaris 2.5.1. --------------------------------------------------------------------- WHAT'S CHANGED Here are the changes since Princeton patch 2: --- We could crash in free_client_info() in dhcp.c, due to freeing a variable that wasn't malloc'd. (Reported by several people.) Thanks to Andreas Steinmetzler , Marc Beuchat , and others, for pointing this out. --- There was a bug in dhcp_request() in dhcp.c. A client would boot and be assigned a dynamic IP address. The client restarted before the lease expired, and came up in INIT-REBOOT state. The server still had the current binding, as it should. The client specified the same IP address it had before in the Requested IP Address option. The server would incorrectly report that current binding was assigned via BootP instead of DHCP, and clear it, then assign a fresh one. (The new assignment could be the same just-freed dynamic IP address, or another dynamic one.) Now the server properly recognizes that current binding was assigned via DHCP and re-uses it. --- Jeff Ross reported the following error appearing repeatedly in syslog: "Tried to assign an ip which already had a binding (ip address here)". I found three likely causes for the problem: 1) When we got a DHCPDISCOVER and do not find a current appropriate binding for this client to re-use, we next checked the client's lastbinding to see if that is appropriate, and if so, re-use it. However, we were failing to check if that IP address was already bound to someone else; now we check that, and if so, do not use that address. If the lastbinding was not present or not appropriate, and the client specified a Requested IP Address option, we check to see if it is appropriate, and if so, use it. However, we were failing to check if that IP address was already bound to someone else; now we check that, and if so, do not use that address. (Changed dhcp_discover() in dhcp.c) 2) The problem could also be caused by the following bug: When we got a DHCPREQUEST from a client that is INIT-REBOOT, and the Requested IP Address is a dynamic IP address, and that address is appropriate for the client, and is not presently bound, we grant it to the client. We were putting it into the ipboundhshtbl, but failing to remove it from the pool of available dynmamic IP addresses. (Changed dhcp_request() in dhcp.c) 3) The problem could also be caused by misconfiguration: If the dhcpd.conf file contains 'network' statements in which the IP addresses ranges overlap, bad things can happen, including this. Added code to get_dynamic_ip() in dynamic.c to provide more diagnostics. Added warning about overlapping 'network' statement IP ranges to the dhcpd.conf sample file. (Though we are not specifically checking for this configuration error; we won't warn in all cases, just those we notice.) --- Jeff Ross and Andrew Smith Andrew Smith saw "hash_Insert(boundhshtbl) failed! Something's wrong!", "not increasing 'leases' counter...so count may no longer be right" messages. I think most of these were cured with the fixes above, but not all. The remaining causes may be associated with the boundhshtbl and ipboundhshtbl falling out of sync. (Both reflect the current bindings; the first is keyed by clientid and the second by ip address.) It's possible that this is triggerred by having multiple clients attempting to use the same clientid. I've added some more text to the error messages, to make it clearer what state we're in when they happen. I've located a couple places where we were letting the two tables fall out of sync, and fixed them. As we always assumed these two tables were in sync, we typically only looked things up in one of the two tables (whichever was more convenient given the data we had). Now we look things up in both tables, and check that everything agrees. If we find that things don't agree, we'll produce more error messages, which may help track down any remaining bugs in this area. Although I've added all those tests, I've not been able to exercise all the paths through the code, as I've not been able to produce most of the pathological condictions they're intended to catch. --- Jay Plett found that dhcp_inform() was not putting the user class value into the reply packet correctly, since it was mistakenly looking at the length of the vendor identifier value. Included his fix. --- Included UnixWare patches from Tim Rice : The INSTALL macro in the top-level Makefile.in is now @INSTALL@ instead of 'install'. (Also from ChrisTengi .) The CC macro in all Makefile.in files is now @CC@ instead of gcc. (Also from Chris Tengi .) The top-level Makefile has a new 'distclean' target you can use to remove all the files built by 'configure'. Added support for socket APIs with "buffer length" size other than int. There's a new CONFIG_SOCKARGLENTYPE def which 'configure' will set to trigger the use of the new socklen_t typedef. configure now tests for and defines SVR4. configure now tests for libgen and sets LIBS appropriately. configure checks for stropts.h and defines a new HAVE_STROPTS_H accordingly. configure now checks for UnixWare, and if found, adds -lresolv to LIBS (needed for strcasecmp), and defines the new XDEFS to be -D_KMEMUSER. The Makefile.in files for dhcpcmd and snmpd now includes XDEFS when setting DEFS, to get the -D_KMEMUSER. Added include of net/if.h to a couple places, include of fcntl.h, stropts.h based on new HAVE_STROPTS_H. The initialtion of servers[] in dhcpcmd.c is now ' { NULL }' instead of '{ }'. (You still need to replace this with your servers if you want to actually use dhcpcmd.) Fixed some variable types and added some casts to eliminate compiler warnings. Added some new-style function prototypes. --- Included Chris Tengi's corrections to man/bootptab.5 to include various missing tags. --- Included Chris Tengi's patch to process_bindata() in readfile.c; 'str' was not being initialized. --- If we have trouble parsing dhcp options, attempt to report the client identifier or chaddr, if possible. --- Updated bootptab(5) man page to describe how the $V, $C, and $DHCP override entries work. Updated references to RFCs and Internet Drafts. Updated to refer to dhcpd, not bootpd. Moved some sections around. --- Some broken or misconfigured clients apparently claim to have the bogus Ethernet address 0:0:0:0:0:0. If the bootp/dhcp header htype==0x01 and chaddr=0x000000000000, we'll log the error and not try to respond. Additionally, if a dhcp packet contains a Client ID of 0x01000000000000, we'll do the same. (The latter is not strictly illegal, but seeing it should tip you off that the client is broken or misconfigured.) Thanks to Jeff Ross . --- Some error messages indicating problems with the request packets that should have been produced at debug level 2 or higher were being produced only at debug level 3 or higher; fixed. --- Jeff Ross reports that OPT is not passed from the top-level Makefile to the rest. Fixed, and also changed to pass DEBUG as well (instead of leaving it always set to define DEBUG in the lower-level makefiles). --- If any of the "Must Be Zero" bits in the 'flags' field (in the header) are set, they used to be copied into the reply packet. We'll now clear them before sending a reply. --- Created man pages for dhcpd(8) and dhcpd.conf(5). They're still a bit rough around the edges. --- In the top-level Makefile.in, I rearranged the definitions for CHECK_FILE_ACCESS, TAB-FILE, CONFIG_FILE, HASHTABLESIZE, and LASTBINDIR so that local customizations will be easier to see. Fixed the completely messed-up PID_FILE example definition. --- Rewrote the 'Installation' document to provide a bit more detail. --- Updated sample/dhcpd.conf.sample2 to agree with the man page. --- Moved README.PRINCETON (the readme file that accompanied Princeton patch number 1) to README.PRINCETON1, to follow the convention the other patches are following. Replaced README.PRINCETON contents with generic text explaining what these patches are and where to obtain them. ========================================================================= Princeton Patch 2 October 29, 1996 APPLYING THE PATCH The patch is against dhcpd version 3.3.7 as distributed by CMU, with Princeton patch version 1 applied. So if you are starting from scratch, first get dhcpd 3.3.7 from CMU, then apply Princeton patch 1 (http://www.princeton.edu/~irwin/src/CMU-dhcpd-3.3.7-PU-patch1.Z), then apply this patch. You may have some local patches you'll need to reconcile against this. --------------------------------------------------------------------- PLATFORMS This code is currently in production at Princeton, but has NOT been tested extensively in all environments. In particular, I've only compiled and tested on SunOS 4.1.4 and Solaris 2.5.1. --------------------------------------------------------------------- WHAT'S CHANGED Here are the changes since Princeton patch 1: We could crash when we got a bootp request if that client currently was in our table of current bindings, but the IP address had been removed from the bootptab. Fixed. We could crash when we received a DHCPDISCOVER if the client had an appropriate static IP address listed in bootptab, and was presently bound via a DHCP assignment. Fixed. If you have defined pools of dynamic addresses, get_dynamic_ip() could spent a long time walking through all the free addresses/pools for a given gateway, every time we considered handing one out. This makes it appear the server is stuck for long periods of time. I sped this up, moving the time-consuming PING of the candidate address to the end, after all other possible tests have been done. Also, instead of testing each candidate's IP address against the gateway's IP address/netmask, instead just test a pool's IP address/netmask against the gateway's, once, before trying to walk a pool. When dumping bindings, show the binding "code" value, indicating how the address was assigned. Added call to create_lease() in dhcp_discover(), as published by Nancy L Wong on mailing list. Removed my less-correct fix in create_stub() that copied lease time from bootptab entry into stub. The result is that info in the bootptab DHCP and VEND dummy entries are now propagated properly to the client. When starting up, provide more detail about the bindings we are reading, assuming debug level is high enough. Added samples/dhcpd.conf.sample2, another sample dhcpd.conf file. This one contains more comments that may better illustrate the use of the various keywords. Added new feature to let you expire infinite (bootp-assigned) dynamic addresses; see section below. As a side effect of this new feature, we *lose* support for specifying 0xFFFFFFFF (infinity) as a possible lease time in bootptab. (I suspect I may have introduced some bugs for the 'roaming' (':ro:') feature, as that's not one I use/test.) --------------------------------------------------------------------- EXPIRE INFINITE DYNAMICS FEATURE I added the capability to expire those assignments made via bootp for dynamic addresses. BootP assignments must normally be recorded as infinite, as the client has no way to time out the assignment. But if you have some external means to ensure that the BootP clients being assigned dynamic addresses will timeout their assignments (e.g. power cycle clients periodically), then you can use the new feature to have the server reclaim those addresses as well, making them available again for re-assignment. To turn on this new server feature, specify the new "expire_infinite_dynamics" keyword in the dhcpd.conf file; it takes a required argument of a time (in seconds). The server will reclaim any infinite (i.e. bootp-assigned) dynamic address after that many seconds. (The reclaim will happen during regular dhcp garbage collection.) If you set expire_infinite_dynamics to 0, or simply leave it out of the dhcp.conf file (it is optional), you get the same old default behavior, which is to never expire these assignments. Note that we don't provide an expire_infinite_statics, since this server does not actually record infinite (bootp-assigned) static assignments in the first place. ========================================================================= Princeton Patch 1 October 14, 1996 APPLYING THE PATCH The patch is against dhcpd version 3.3.7 as distributed by CMU. You may have some local patches you'll need to reconcile against this. I've included some of the changes others have suggested on the CMU bootpd mailing list, since I was able to test them here. (I've *not* dealt with the gcc -I issue in the Makefile. If you've dealt with that already, you know what to do. If that issue wasn't a problem for, then never mind.) -----------------------------------------------------------