add back in udhcp support
This commit was genuinely broken at the time (not related to our build system): scripts/config/mkconfigs.c (2005-08-01 - 2006-10-05 arasi) uretilen bbconfigopts.h icine .config satirlarini kacissiz, ham newline'larla gömüyordu - gecerli C degildi, busybox'un kendi bb_mkdep araci bile parse edemiyordu (7d219aab7 ile duzeltildi, mkconfigs shell scripte cevrildi)
No binary (build failed)
—
(log yok)
| @@ -95,6 +95,7 @@ USE_DPKG(APPLET(dpkg, dpkg, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | |
| USE_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, _BB_DIR_USR_BIN, _BB_SUID_NEVER, dpkg_deb)) | |
| USE_DU(APPLET(du, du, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | |
| USE_DUMPKMAP(APPLET(dumpkmap, dumpkmap, _BB_DIR_BIN, _BB_SUID_NEVER)) | |
| + | USE_DUMPLEASES(APPLET(dumpleases, dumpleases, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
| USE_E2FSCK(APPLET(e2fsck, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER)) | |
| USE_E2LABEL(APPLET_NOUSAGE(e2label, tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER)) | |
| USE_ECHO(APPLET(echo, echo, _BB_DIR_BIN, _BB_SUID_NEVER)) | |
| @@ -273,6 +274,8 @@ USE_TRACEROUTE(APPLET(traceroute, traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) | |
| USE_TRUE(APPLET(true, true, _BB_DIR_BIN, _BB_SUID_NEVER)) | |
| USE_TTY(APPLET(tty, tty, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | |
| USE_TUNE2FS(APPLET(tune2fs, tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER)) | |
| + | USE_UDHCPC(APPLET(udhcpc, udhcpc, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
| + | USE_UDHCPD(APPLET(udhcpd, udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) |
| USE_UMOUNT(APPLET(umount, umount, _BB_DIR_BIN, _BB_SUID_NEVER)) | |
| USE_UNAME(APPLET(uname, uname, _BB_DIR_BIN, _BB_SUID_NEVER)) | |
| USE_UNCOMPRESS(APPLET(uncompress, uncompress, _BB_DIR_BIN, _BB_SUID_NEVER)) | |
| @@ -0,0 +1,13 @@ | |
| + | udhcp server/client package |
| + | ----------------------- |
| + | |
| + | Russ Dill <[email protected]> |
| + | Matthew Ramsay <[email protected]> |
| + | Chris Trew <[email protected]> |
| + | |
| + | Other Credits: |
| + | -------------- |
| + | Moreton Bay (http://www.moretonbay.com/) |
| + | Vladimir Oleynik <[email protected]> Size optimizations |
| + | |
| + | |
| @@ -0,0 +1,339 @@ | |
| + | GNU GENERAL PUBLIC LICENSE |
| + | Version 2, June 1991 |
| + | |
| + | Copyright (C) 1989, 1991 Free Software Foundation, Inc. |
| + | 675 Mass Ave, Cambridge, MA 02139, USA |
| + | Everyone is permitted to copy and distribute verbatim copies |
| + | of this license document, but changing it is not allowed. |
| + | |
| + | Preamble |
| + | |
| + | The licenses for most software are designed to take away your |
| + | freedom to share and change it. By contrast, the GNU General Public |
| + | License is intended to guarantee your freedom to share and change free |
| + | software--to make sure the software is free for all its users. This |
| + | General Public License applies to most of the Free Software |
| + | Foundation's software and to any other program whose authors commit to |
| + | using it. (Some other Free Software Foundation software is covered by |
| + | the GNU Library General Public License instead.) You can apply it to |
| + | your programs, too. |
| + | |
| + | When we speak of free software, we are referring to freedom, not |
| + | price. Our General Public Licenses are designed to make sure that you |
| + | have the freedom to distribute copies of free software (and charge for |
| + | this service if you wish), that you receive source code or can get it |
| + | if you want it, that you can change the software or use pieces of it |
| + | in new free programs; and that you know you can do these things. |
| + | |
| + | To protect your rights, we need to make restrictions that forbid |
| + | anyone to deny you these rights or to ask you to surrender the rights. |
| + | These restrictions translate to certain responsibilities for you if you |
| + | distribute copies of the software, or if you modify it. |
| + | |
| + | For example, if you distribute copies of such a program, whether |
| + | gratis or for a fee, you must give the recipients all the rights that |
| + | you have. You must make sure that they, too, receive or can get the |
| + | source code. And you must show them these terms so they know their |
| + | rights. |
| + | |
| + | We protect your rights with two steps: (1) copyright the software, and |
| + | (2) offer you this license which gives you legal permission to copy, |
| + | distribute and/or modify the software. |
| + | |
| + | Also, for each author's protection and ours, we want to make certain |
| + | that everyone understands that there is no warranty for this free |
| + | software. If the software is modified by someone else and passed on, we |
| + | want its recipients to know that what they have is not the original, so |
| + | that any problems introduced by others will not reflect on the original |
| + | authors' reputations. |
| + | |
| + | Finally, any free program is threatened constantly by software |
| + | patents. We wish to avoid the danger that redistributors of a free |
| + | program will individually obtain patent licenses, in effect making the |
| + | program proprietary. To prevent this, we have made it clear that any |
| + | patent must be licensed for everyone's free use or not licensed at all. |
| + | |
| + | The precise terms and conditions for copying, distribution and |
| + | modification follow. |
| + | |
| + | GNU GENERAL PUBLIC LICENSE |
| + | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
| + | |
| + | 0. This License applies to any program or other work which contains |
| + | a notice placed by the copyright holder saying it may be distributed |
| + | under the terms of this General Public License. The "Program", below, |
| + | refers to any such program or work, and a "work based on the Program" |
| + | means either the Program or any derivative work under copyright law: |
| + | that is to say, a work containing the Program or a portion of it, |
| + | either verbatim or with modifications and/or translated into another |
| + | language. (Hereinafter, translation is included without limitation in |
| + | the term "modification".) Each licensee is addressed as "you". |
| + | |
| + | Activities other than copying, distribution and modification are not |
| + | covered by this License; they are outside its scope. The act of |
| + | running the Program is not restricted, and the output from the Program |
| + | is covered only if its contents constitute a work based on the |
| + | Program (independent of having been made by running the Program). |
| + | Whether that is true depends on what the Program does. |
| + | |
| + | 1. You may copy and distribute verbatim copies of the Program's |
| + | source code as you receive it, in any medium, provided that you |
| + | conspicuously and appropriately publish on each copy an appropriate |
| + | copyright notice and disclaimer of warranty; keep intact all the |
| + | notices that refer to this License and to the absence of any warranty; |
| + | and give any other recipients of the Program a copy of this License |
| + | along with the Program. |
| + | |
| + | You may charge a fee for the physical act of transferring a copy, and |
| + | you may at your option offer warranty protection in exchange for a fee. |
| + | |
| + | 2. You may modify your copy or copies of the Program or any portion |
| + | of it, thus forming a work based on the Program, and copy and |
| + | distribute such modifications or work under the terms of Section 1 |
| + | above, provided that you also meet all of these conditions: |
| + | |
| + | a) You must cause the modified files to carry prominent notices |
| + | stating that you changed the files and the date of any change. |
| + | |
| + | b) You must cause any work that you distribute or publish, that in |
| + | whole or in part contains or is derived from the Program or any |
| + | part thereof, to be licensed as a whole at no charge to all third |
| + | parties under the terms of this License. |
| + | |
| + | c) If the modified program normally reads commands interactively |
| + | when run, you must cause it, when started running for such |
| + | interactive use in the most ordinary way, to print or display an |
| + | announcement including an appropriate copyright notice and a |
| + | notice that there is no warranty (or else, saying that you provide |
| + | a warranty) and that users may redistribute the program under |
| + | these conditions, and telling the user how to view a copy of this |
| + | License. (Exception: if the Program itself is interactive but |
| + | does not normally print such an announcement, your work based on |
| + | the Program is not required to print an announcement.) |
| + | |
| + | These requirements apply to the modified work as a whole. If |
| + | identifiable sections of that work are not derived from the Program, |
| + | and can be reasonably considered independent and separate works in |
| + | themselves, then this License, and its terms, do not apply to those |
| + | sections when you distribute them as separate works. But when you |
| + | distribute the same sections as part of a whole which is a work based |
| + | on the Program, the distribution of the whole must be on the terms of |
| + | this License, whose permissions for other licensees extend to the |
| + | entire whole, and thus to each and every part regardless of who wrote it. |
| + | |
| + | Thus, it is not the intent of this section to claim rights or contest |
| + | your rights to work written entirely by you; rather, the intent is to |
| + | exercise the right to control the distribution of derivative or |
| + | collective works based on the Program. |
| + | |
| + | In addition, mere aggregation of another work not based on the Program |
| + | with the Program (or with a work based on the Program) on a volume of |
| + | a storage or distribution medium does not bring the other work under |
| + | the scope of this License. |
| + | |
| + | 3. You may copy and distribute the Program (or a work based on it, |
| + | under Section 2) in object code or executable form under the terms of |
| + | Sections 1 and 2 above provided that you also do one of the following: |
| + | |
| + | a) Accompany it with the complete corresponding machine-readable |
| + | source code, which must be distributed under the terms of Sections |
| + | 1 and 2 above on a medium customarily used for software interchange; or, |
| + | |
| + | b) Accompany it with a written offer, valid for at least three |
| + | years, to give any third party, for a charge no more than your |
| + | cost of physically performing source distribution, a complete |
| + | machine-readable copy of the corresponding source code, to be |
| + | distributed under the terms of Sections 1 and 2 above on a medium |
| + | customarily used for software interchange; or, |
| + | |
| + | c) Accompany it with the information you received as to the offer |
| + | to distribute corresponding source code. (This alternative is |
| + | allowed only for noncommercial distribution and only if you |
| + | received the program in object code or executable form with such |
| + | an offer, in accord with Subsection b above.) |
| + | |
| + | The source code for a work means the preferred form of the work for |
| + | making modifications to it. For an executable work, complete source |
| + | code means all the source code for all modules it contains, plus any |
| + | associated interface definition files, plus the scripts used to |
| + | control compilation and installation of the executable. However, as a |
| + | special exception, the source code distributed need not include |
| + | anything that is normally distributed (in either source or binary |
| + | form) with the major components (compiler, kernel, and so on) of the |
| + | operating system on which the executable runs, unless that component |
| + | itself accompanies the executable. |
| + | |
| + | If distribution of executable or object code is made by offering |
| + | access to copy from a designated place, then offering equivalent |
| + | access to copy the source code from the same place counts as |
| + | distribution of the source code, even though third parties are not |
| + | compelled to copy the source along with the object code. |
| + | |
| + | 4. You may not copy, modify, sublicense, or distribute the Program |
| + | except as expressly provided under this License. Any attempt |
| + | otherwise to copy, modify, sublicense or distribute the Program is |
| + | void, and will automatically terminate your rights under this License. |
| + | However, parties who have received copies, or rights, from you under |
| + | this License will not have their licenses terminated so long as such |
| + | parties remain in full compliance. |
| + | |
| + | 5. You are not required to accept this License, since you have not |
| + | signed it. However, nothing else grants you permission to modify or |
| + | distribute the Program or its derivative works. These actions are |
| + | prohibited by law if you do not accept this License. Therefore, by |
| + | modifying or distributing the Program (or any work based on the |
| + | Program), you indicate your acceptance of this License to do so, and |
| + | all its terms and conditions for copying, distributing or modifying |
| + | the Program or works based on it. |
| + | |
| + | 6. Each time you redistribute the Program (or any work based on the |
| + | Program), the recipient automatically receives a license from the |
| + | original licensor to copy, distribute or modify the Program subject to |
| + | these terms and conditions. You may not impose any further |
| + | restrictions on the recipients' exercise of the rights granted herein. |
| + | You are not responsible for enforcing compliance by third parties to |
| + | this License. |
| + | |
| + | 7. If, as a consequence of a court judgment or allegation of patent |
| + | infringement or for any other reason (not limited to patent issues), |
| + | conditions are imposed on you (whether by court order, agreement or |
| + | otherwise) that contradict the conditions of this License, they do not |
| + | excuse you from the conditions of this License. If you cannot |
| + | distribute so as to satisfy simultaneously your obligations under this |
| + | License and any other pertinent obligations, then as a consequence you |
| + | may not distribute the Program at all. For example, if a patent |
| + | license would not permit royalty-free redistribution of the Program by |
| + | all those who receive copies directly or indirectly through you, then |
| + | the only way you could satisfy both it and this License would be to |
| + | refrain entirely from distribution of the Program. |
| + | |
| + | If any portion of this section is held invalid or unenforceable under |
| + | any particular circumstance, the balance of the section is intended to |
| + | apply and the section as a whole is intended to apply in other |
| + | circumstances. |
| + | |
| + | It is not the purpose of this section to induce you to infringe any |
| + | patents or other property right claims or to contest validity of any |
| + | such claims; this section has the sole purpose of protecting the |
| + | integrity of the free software distribution system, which is |
| + | implemented by public license practices. Many people have made |
| + | generous contributions to the wide range of software distributed |
| + | through that system in reliance on consistent application of that |
| + | system; it is up to the author/donor to decide if he or she is willing |
| + | to distribute software through any other system and a licensee cannot |
| + | impose that choice. |
| + | |
| + | This section is intended to make thoroughly clear what is believed to |
| + | be a consequence of the rest of this License. |
| + | |
| + | 8. If the distribution and/or use of the Program is restricted in |
| + | certain countries either by patents or by copyrighted interfaces, the |
| + | original copyright holder who places the Program under this License |
| + | may add an explicit geographical distribution limitation excluding |
| + | those countries, so that distribution is permitted only in or among |
| + | countries not thus excluded. In such case, this License incorporates |
| + | the limitation as if written in the body of this License. |
| + | |
| + | 9. The Free Software Foundation may publish revised and/or new versions |
| + | of the General Public License from time to time. Such new versions will |
| + | be similar in spirit to the present version, but may differ in detail to |
| + | address new problems or concerns. |
| + | |
| + | Each version is given a distinguishing version number. If the Program |
| + | specifies a version number of this License which applies to it and "any |
| + | later version", you have the option of following the terms and conditions |
| + | either of that version or of any later version published by the Free |
| + | Software Foundation. If the Program does not specify a version number of |
| + | this License, you may choose any version ever published by the Free Software |
| + | Foundation. |
| + | |
| + | 10. If you wish to incorporate parts of the Program into other free |
| + | programs whose distribution conditions are different, write to the author |
| + | to ask for permission. For software which is copyrighted by the Free |
| + | Software Foundation, write to the Free Software Foundation; we sometimes |
| + | make exceptions for this. Our decision will be guided by the two goals |
| + | of preserving the free status of all derivatives of our free software and |
| + | of promoting the sharing and reuse of software generally. |
| + | |
| + | NO WARRANTY |
| + | |
| + | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |
| + | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN |
| + | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |
| + | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED |
| + | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| + | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS |
| + | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE |
| + | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, |
| + | REPAIR OR CORRECTION. |
| + | |
| + | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
| + | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
| + | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, |
| + | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING |
| + | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED |
| + | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY |
| + | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER |
| + | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |
| + | POSSIBILITY OF SUCH DAMAGES. |
| + | |
| + | END OF TERMS AND CONDITIONS |
| + | |
| + | Appendix: How to Apply These Terms to Your New Programs |
| + | |
| + | If you develop a new program, and you want it to be of the greatest |
| + | possible use to the public, the best way to achieve this is to make it |
| + | free software which everyone can redistribute and change under these terms. |
| + | |
| + | To do so, attach the following notices to the program. It is safest |
| + | to attach them to the start of each source file to most effectively |
| + | convey the exclusion of warranty; and each file should have at least |
| + | the "copyright" line and a pointer to where the full notice is found. |
| + | |
| + | <one line to give the program's name and a brief idea of what it does.> |
| + | Copyright (C) 19yy <name of author> |
| + | |
| + | This program is free software; you can redistribute it and/or modify |
| + | it under the terms of the GNU General Public License as published by |
| + | the Free Software Foundation; either version 2 of the License, or |
| + | (at your option) any later version. |
| + | |
| + | This program is distributed in the hope that it will be useful, |
| + | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | GNU General Public License for more details. |
| + | |
| + | You should have received a copy of the GNU General Public License |
| + | along with this program; if not, write to the Free Software |
| + | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | |
| + | Also add information on how to contact you by electronic and paper mail. |
| + | |
| + | If the program is interactive, make it output a short notice like this |
| + | when it starts in an interactive mode: |
| + | |
| + | Gnomovision version 69, Copyright (C) 19yy name of author |
| + | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
| + | This is free software, and you are welcome to redistribute it |
| + | under certain conditions; type `show c' for details. |
| + | |
| + | The hypothetical commands `show w' and `show c' should show the appropriate |
| + | parts of the General Public License. Of course, the commands you use may |
| + | be called something other than `show w' and `show c'; they could even be |
| + | mouse-clicks or menu items--whatever suits your program. |
| + | |
| + | You should also get your employer (if you work as a programmer) or your |
| + | school, if any, to sign a "copyright disclaimer" for the program, if |
| + | necessary. Here is a sample; alter the names: |
| + | |
| + | Yoyodyne, Inc., hereby disclaims all copyright interest in the program |
| + | `Gnomovision' (which makes passes at compilers) written by James Hacker. |
| + | |
| + | <signature of Ty Coon>, 1 April 1989 |
| + | Ty Coon, President of Vice |
| + | |
| + | This General Public License does not permit incorporating your program into |
| + | proprietary programs. If your program is a subroutine library, you may |
| + | consider it more useful to permit linking proprietary applications with the |
| + | library. If this is what you want to do, use the GNU Library General |
| + | Public License instead of this License. |
| @@ -0,0 +1,260 @@ | |
| + | 0.9.9 (pending) |
| + | + Various other size optimizations (Vladimir) |
| + | + Change strerror(errno) to %m (Vladimir N. Oleynik <[email protected]>) |
| + | + Fixed a little endian problem in mton (Bastian Blank <[email protected]>) |
| + | + Fixed a arpping alignment problem (Rui He <[email protected]>) |
| + | + Added sanity check for max_leases (udhcp bug #1285) (me) |
| + | + Finally got rid of the trailing space in enviromental vars (me) |
| + | + added an new enviromental variable: $mask. It contains the number |
| + | of subnet bits for tools like ip route that require it. |
| + | (Bastian Blank <[email protected]>, me) |
| + | |
| + | 0.9.8 (021031) |
| + | + split up README files (me) |
| + | + use /dev/urandom to seed xid's (instead of time(0)) (me) |
| + | + fixed renew behavior (me) |
| + | + udhcp now fits nicely into busybox |
| + | (Glenn McGrath <[email protected]> as well as myself) |
| + | + updated client manpage (me) |
| + | + both client and server now use sockets for signal handling, |
| + | hopefully, this will be the last needed change in signal |
| + | handling, I'm fairly certain all the possible races are now |
| + | closed. (me) |
| + | + The server now restarts the auto_time timer when it receives |
| + | a SIGUSR1 (write out config file). (me) |
| + | + Improve signal handling (David Poole) |
| + | + Fix to config file parsing (Matt Kraai) |
| + | + Fix load lease logic (me) |
| + | + Fix clear_lease logic (me) |
| + | + -h is now an alias for -H (udhcp bug #1253) |
| + | + Shorter timeout on not receiving offers (me) |
| + | + Improved signal behavior by client (me) |
| + | + Would never assign end address (Keith Smith <[email protected]>) |
| + | + Was improperly reporting yiaddr as siaddr ([email protected]) |
| + | udhcp bug#1256 |
| + | + Fixed reading of client id (David Poole <[email protected]>) |
| + | + change sys_errlist[] to strerror() as it aparently doesn't exist |
| + | (Erik Andersen <[email protected]>) |
| + | + fixed get_raw_packet so it returns -2 on non fatal errors |
| + | (Ted Lemon <[email protected]>) |
| + | + Improved (hopefully) NAKing behavior (me) |
| + | + Added -b option (Jouni Malinen) |
| + | + Compute checksums correctly on big endian hosts |
| + | (Jouni Malinen <[email protected]>) |
| + | |
| + | 0.9.7 (020526) |
| + | + Use add_lease in read_leases, sanitizes leases more, and clears out exprired |
| + | ones if there is no more room (me) |
| + | + Moved udhcpd.leases to /var/lib/misc/udhcpd.leases (Debian bug #147747) |
| + | + Change (obsolete) AF_INET in arping.c to PF_PACKET (Debian bug #127049) |
| + | + Added script hook for DHCPNAK (nak), as well as providing the message option |
| + | (me) |
| + | + Generate the paramaters request list by seeing what options in options.c are |
| + | ored with OPTION_REQ in options.c |
| + | + Fix dhcp renew forgetfullness on client (bug #1230) |
| + | + Fix dhcp release bug on client (bug #1231) |
| + | + Set option request list for DHCP renew (bug #1233) |
| + | + Set BOOTREQUEST/REPLY properly |
| + | + Change client-identifier field to popularly expected behavior (me) |
| + | + Only reopen port on errors (me) |
| + | + Change fork/close/setsid structures to daemon() (me) |
| + | + Allow user to specify udhcpd config file at run time (Steven, me) |
| + | + Write pidfile after changing it (Steven CTR Carr <[email protected]>) |
| + | + Added env var docs to udhcpc man page (Matt) |
| + | + Standardized lowercase udhcp in documentation (me) |
| + | + Accept packets without a UDP checksum (me) |
| + | + Accept packets with extra garbage (me) |
| + | + Better error handling in files.c (me) |
| + | + Combined read_interface function to reduce COMBINED_BINARY size (me) |
| + | + Drop calc_length(), some servers choke on smaller packets (me) |
| + | + Try to clean some fat out (me) |
| + | |
| + | 0.9.6 (011001) |
| + | + Added bootp paramaters to server (me) |
| + | + Added bootp paramaters to client (me) |
| + | + Added vendor id to client (me) |
| + | + Better pidfile handling in client and server (me) |
| + | + Added man pages (Matt Kraai <[email protected]>) |
| + | |
| + | 0.9.5 (010914) |
| + | + Fixed $HOME and $PATH env passing (me) |
| + | + Fixed client to only listen for raw packets on correct interface (me) |
| + | + added --quit,-q option to quit after a lease is obtained (me) |
| + | + Fixed 100% CPU utilization by client when interface is down (me) |
| + | |
| + | 0.9.4 (010827) |
| + | + Force broadcast to broken clients that request unicast (ie, MSFT 98) |
| + | + Make install rules (Adam J. Richter <[email protected]>) |
| + | + One scripts, instead of many (Adam) |
| + | + Removed script paramater info files (env vars only) (Adam) |
| + | + Controlling of forking behavior in client (Adam) |
| + | + General script.c/dhcpc.c cleanups (Adam) |
| + | |
| + | 0.9.3 (010820) |
| + | + Increased debugging verbosity (me) |
| + | + Cut trailing whitespace when reading config file (me) |
| + | + added hostname option to client (me) |
| + | + fixed a strncpy bug in script.c (me) |
| + | + fixed a leaky socket in dhcpc.c (me) |
| + | + fixed a leaky socket in dhcpd.c (me) |
| + | |
| + | 0.9.2 (010810) |
| + | + Added raw sockets to client (me) |
| + | + alignment fixes (Mark Huang) |
| + | + compiler warning fixes (Mark Huang) |
| + | + client now sends parameter list (Mark Huang/me) |
| + | + added ipttl option |
| + | + Does now not request broadcast packets |
| + | |
| + | 0.9.1 (010806) |
| + | + Added udhcpc client |
| + | + reorganized functions/files |
| + | + listening socket now only binds to one interface |
| + | |
| + | 0.9.0 (010720) Major rewrite, current changes, goals: |
| + | + should not segfault on bogus packets. |
| + | + Options can be read from sname and file fields. |
| + | + supports all DHCP messages (release, decline, inform). |
| + | + IP block is now specified by a range of IP's. |
| + | + Leases file now contains lease time (relative, or absolute). |
| + | + Just about any DHCP option is now supported. |
| + | + DNS entries are no longer read from resolv.conf |
| + | + Lease file can be written periodically when the process receives a SIGUSR1 |
| + | + arpping should be supported on all arches. |
| + | + support for DHCP relays. |
| + | + DHCP messages can be unicast if the client requests it. |
| + | + many, many, many other things. |
| + | |
| + | 0.8.29 (000323) |
| + | + stable(?) release |
| + | |
| + | |
| + | 0.8.28 (000323) |
| + | + removed alarm as it was causing server to go down |
| + | + removed debugging |
| + | + break down dhcpd.c into manageable files |
| + | |
| + | |
| + | 0.8.27 (000221) |
| + | + OFFER also sends gateway/subnet (for picky dhcp clients) |
| + | + multiple DNS now handled from resolv.conf if available |
| + | + multiple WINS (from dhcpd.conf) |
| + | |
| + | 0.8.25 (000120) |
| + | + now compiles *and* runs on a generic linux system |
| + | tested with a windows 98 client and the sample config |
| + | files in the samples directory. |
| + | |
| + | 0.8.24 (000117) |
| + | + makeiplist tool has basic functionality in place |
| + | + new sample config files |
| + | + route add -host 255.255.255.255 dev eth0 added for generic linux |
| + | |
| + | 0.8.23 (000117) |
| + | + NETtel specific fix for ignoring dhcp requests on 2nd interface |
| + | |
| + | 0.8.22 (000113) |
| + | + minor changes to compile under a generic linux system |
| + | + minor config file location changes for a generic linux system |
| + | + makeiplist fixes.. still incomplete.. but etting closer |
| + | |
| + | 0.8.21 (000113) |
| + | + now sends the correct server ip instead of hardcoded value |
| + | + minor debugging fixes for critical messages |
| + | |
| + | 0.8.20 (000106) |
| + | + cut out dhcp server checking.. this was causing dialout ppp |
| + | sessions with idle time set to never time out. |
| + | + also removed the 10 second pause before launching.. as this |
| + | was originally to stop it replying to a dhcp client |
| + | on a NETtel which was really a bad way to do it in the |
| + | first place :-) |
| + | |
| + | 0.8.19 (000104) |
| + | + fixes for route add -host on a machine that needs to run both |
| + | a DHCP client and server (dual eth box) |
| + | |
| + | 0.8.18 (991220) |
| + | |
| + | + Race conditions fixed by disabling alarm whilst the server is busy |
| + | + Fixed continous clearing of the offered array so that it is only cleared |
| + | when it is dirty - (could change the position of when dirty is set) |
| + | |
| + | 0.8.17 (991212) |
| + | |
| + | - has problems clearing out the offered array |
| + | |
| + | 0.8.16 (991203) |
| + | + Non blocking error is changes to informational as it is not really |
| + | an error |
| + | |
| + | 0.8.15 (991129) |
| + | + Servs the dns field 3 times (Nettel only) so that windows servers |
| + | dont time out whilst nettel is booting |
| + | |
| + | 0.8.14 (991126) |
| + | + added owner check for the offered array so clean out time may be |
| + | increased |
| + | + added new func to print out chadder/MAC |
| + | |
| + | 0.8.13 (991125) |
| + | + added win95 support (w95 changed xid halfway through conversation) |
| + | + had to change the offered array to use hardware addresses instead of xid |
| + | + fixed re offered bug |
| + | + added more debugging |
| + | |
| + | 0.8.12 (991111) |
| + | + debugging was real bad.. cleaned up a bit.. needs overhaul |
| + | |
| + | |
| + | 0.8.11 (991110) |
| + | + fixed up offeredAddr array to actually be used now!! offeredAddr is |
| + | used to see if another simultaneous connecting client was offered |
| + | an address that we are about to offer another client (multiple |
| + | client bug) |
| + | + removed re_offered variable as it breaks multiple client support |
| + | + added lease time to ACK -- doesn't work if in OFFER |
| + | + decreased internal array clear delay to 60 seconds |
| + | + minor findAddr bug (returning -1 instead of 0) |
| + | + if clients xid already in offeredAddr offer the same addr and don't add a |
| + | new addr to offered (caused by a client issuing multiple DISCOVERs) |
| + | |
| + | 0.8.10 (991105) |
| + | + \n bug in arpping |
| + | + minor debugging changes (removed printfs etc) |
| + | + started browseiplist (not finished) |
| + | |
| + | 0.8.9 (19991105) |
| + | + fixed options array size bug (options were cut off) |
| + | |
| + | 0.8.8 (19991105) |
| + | + ignores requests from dhcpcd on the same machine |
| + | |
| + | 0.8.7 (19991104) |
| + | + don't die if we can't bind to search for existing DHCP server |
| + | + slightly more verbose syslogging |
| + | |
| + | 0.8.6 (19991103) |
| + | + added makeiplist (not finished -- core dumps) |
| + | + minor debug changes |
| + | |
| + | 0.8.5 (19991029) |
| + | + exits if another DHCP server is already on the network |
| + | + added Linux Makefile |
| + | |
| + | 0.8.4 (19991026) |
| + | + minor bug fix in findaddr preventing an addr being found |
| + | |
| + | 0.8.3 (19991025) |
| + | + fixed up debugging |
| + | + minor hwaddr issues |
| + | |
| + | 0.8.2 (19991022) |
| + | + free leases (new arpping code from dhcpcd) |
| + | + fixed bug where crashes if no leases/iplist file |
| + | + syslogging and debugging switch |
| + | + serve DNS from resolv.conf |
| + | + fixed bug where new lease added if same mac offered |
| + | + now checks the ip is free b4 offering |
| + | + now supports wins server |
| + | |
| @@ -0,0 +1,62 @@ | |
| + | # |
| + | # For a description of the syntax of this configuration file, |
| + | # see scripts/kbuild/config-language.txt. |
| + | # |
| + | |
| + | menu "udhcp Server/Client" |
| + | |
| + | config CONFIG_UDHCPD |
| + | bool "udhcp Server (udhcpd)" |
| + | default n |
| + | help |
| + | uDHCPd is a DHCP server geared primarily toward embedded systems, |
| + | while striving to be fully functional and RFC compliant. |
| + | |
| + | See http://udhcp.busybox.net for further details. |
| + | |
| + | config CONFIG_UDHCPC |
| + | bool "udhcp Client (udhcpc)" |
| + | default n |
| + | help |
| + | uDHCPc is a DHCP client geared primarily toward embedded systems, |
| + | while striving to be fully functional and RFC compliant. |
| + | |
| + | The udhcp client negotiates a lease with the DHCP server and |
| + | notifies a set of scripts when a lease is obtained or lost. |
| + | |
| + | See http://udhcp.busybox.net for further details. |
| + | |
| + | config CONFIG_DUMPLEASES |
| + | bool "Lease display utility (dumpleases)" |
| + | default n |
| + | depends on CONFIG_UDHCPD |
| + | help |
| + | dumpleases displays the leases written out by the udhcpd server. |
| + | Lease times are stored in the file by time remaining in lease, or |
| + | by the absolute time that it expires in seconds from epoch. |
| + | |
| + | See http://udhcp.busybox.net for further details. |
| + | |
| + | config CONFIG_FEATURE_UDHCP_SYSLOG |
| + | bool " Log udhcp messages to syslog (instead of stdout)" |
| + | default n |
| + | depends on CONFIG_UDHCPD || CONFIG_UDHCPC |
| + | help |
| + | If selected, udhcpd will log all its messages to syslog, otherwise, |
| + | it will attempt to log them to stdout. |
| + | |
| + | See http://udhcp.busybox.net for further details. |
| + | |
| + | config CONFIG_FEATURE_UDHCP_DEBUG |
| + | bool " Compile udhcp with noisy debugging messages" |
| + | default n |
| + | depends on CONFIG_UDHCPD || CONFIG_UDHCPC |
| + | help |
| + | If selected, udhcpd will output extra debugging output. If using |
| + | this option, compile uDHCP with "-g", and do not fork the daemon to |
| + | the background. |
| + | |
| + | See http://udhcp.busybox.net for further details. |
| + | |
| + | endmenu |
| + | |
| @@ -0,0 +1,5 @@ | |
| + | ifneq ($(wildcard ../../networking/Config.in),) |
| + | include Makefile.busybox |
| + | else |
| + | include Makefile.udhcp |
| + | endif |
| @@ -0,0 +1,36 @@ | |
| + | # Makefile for busybox |
| + | # |
| + | # Copyright (C) 1999-2004 by Erik Andersen <[email protected]> |
| + | # |
| + | # This program is free software; you can redistribute it and/or modify |
| + | # it under the terms of the GNU General Public License as published by |
| + | # the Free Software Foundation; either version 2 of the License, or |
| + | # (at your option) any later version. |
| + | # |
| + | # This program is distributed in the hope that it will be useful, |
| + | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + | # General Public License for more details. |
| + | # |
| + | # You should have received a copy of the GNU General Public License |
| + | # along with this program; if not, write to the Free Software |
| + | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| + | # |
| + | |
| + | ifndef top_srcdir |
| + | top_srcdir=../.. |
| + | endif |
| + | ifndef top_builddir |
| + | top_builddir=../.. |
| + | endif |
| + | srcdir=$(top_srcdir)/networking/udhcp |
| + | UDHCP_DIR:=./ |
| + | include $(top_builddir)/Rules.mak |
| + | include $(top_builddir)/.config |
| + | include Makefile.in |
| + | all: $(libraries-y) |
| + | -include $(top_builddir)/.depend |
| + | |
| + | clean: |
| + | rm -f *.o *.a $(AR_TARGET) |
| + | |
| @@ -0,0 +1,53 @@ | |
| + | # Makefile for busybox |
| + | # |
| + | # Copyright (C) 1999-2004 by Erik Andersen <[email protected]> |
| + | # |
| + | # Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
| + | # |
| + | |
| + | UDHCP_AR:=udhcp.a |
| + | ifndef $(UDHCP_DIR) |
| + | UDHCP_DIR:=$(top_builddir)/networking/udhcp/ |
| + | endif |
| + | srcdir=$(top_srcdir)/networking/udhcp |
| + | |
| + | #ok, so I forgot how to do an or, but this is a quick and dirty hack |
| + | ifeq ($(strip $(CONFIG_UDHCPC)),y) |
| + | CONFIG_UDHCP_SHARED=y |
| + | else |
| + | ifeq ($(strip $(CONFIG_UDHCPD)),y) |
| + | CONFIG_UDHCP_SHARED=y |
| + | else |
| + | CONFIG_UDHCP_SHARED=n |
| + | endif |
| + | endif |
| + | |
| + | UDHCP-y:= |
| + | UDHCP-$(CONFIG_UDHCP_SHARED) += common.c options.c packet.c pidfile.c \ |
| + | signalpipe.c socket.c |
| + | UDHCP-$(CONFIG_UDHCPC) += dhcpc.c clientpacket.c clientsocket.c \ |
| + | script.c |
| + | UDHCP-$(CONFIG_UDHCPD) += dhcpd.c arpping.c files.c leases.c \ |
| + | serverpacket.c static_leases.c |
| + | UDHCP-$(CONFIG_DUMPLEASES) += dumpleases.c |
| + | UDHCP_OBJS:=$(patsubst %.c,$(UDHCP_DIR)%.o, $(UDHCP-y)) |
| + | |
| + | ifneq ($(strip $(UDHCP-y)),) |
| + | libraries-y+=$(UDHCP_DIR)$(UDHCP_AR) |
| + | endif |
| + | |
| + | UDHCP-y:=$(patsubst %,$(srcdir)/%,$(UDHCP-y)) |
| + | UDHCP-a:=$(wildcard $(srcdir)/*.c) |
| + | APPLET_SRC-y+=$(UDHCP-y) |
| + | APPLET_SRC-a+=$(UDHCP-a) |
| + | |
| + | UDHCP_INCLUDES:=$(srcdir) |
| + | |
| + | APPLETS_DEFINE-y+=-DIN_BUSYBOX -I$(UDHCP_INCLUDES) |
| + | APPLETS_DEFINE-a+=-DIN_BUSYBOX -I$(UDHCP_INCLUDES) |
| + | |
| + | $(UDHCP_DIR)$(UDHCP_AR): $(UDHCP_OBJS) |
| + | $(do_ar) |
| + | |
| + | $(UDHCP_OBJS): $(UDHCP_DIR)%.o : $(srcdir)/%.c |
| + | $(compile.c) -DIN_BUSYBOX |
| @@ -0,0 +1,110 @@ | |
| + | # udhcp makefile |
| + | |
| + | DESTDIR = |
| + | prefix = /usr |
| + | SBINDIR = /sbin |
| + | USRSBINDIR = $(DESTDIR)$(prefix)/sbin |
| + | USRBINDIR = $(DESTDIR)$(prefix)/bin |
| + | USRSHAREDIR = $(DESTDIR)$(prefix)/share |
| + | |
| + | # Uncomment this to get a shared binary. Call as udhcpd for the server, |
| + | # and udhcpc for the client |
| + | #COMBINED_BINARY=1 |
| + | |
| + | # Uncomment this for extra output and to compile with debugging symbols |
| + | #UDHCP_DEBUG=1 |
| + | |
| + | # Uncomment this to output messages to syslog, otherwise, messages go to stdout |
| + | #UDHCP_SYSLOG=1 |
| + | |
| + | # Set to the prefix of your cross-compiler |
| + | #CROSS_COMPILE=arm-uclibc- |
| + | |
| + | |
| + | #---------------------------------------------------# |
| + | # You should not have to change anything below here # |
| + | #---------------------------------------------------# |
| + | |
| + | CC = $(CROSS_COMPILE)gcc |
| + | LD = $(CROSS_COMPILE)gcc |
| + | INSTALL = install |
| + | |
| + | OBJS_SHARED = common.o options.o packet.o pidfile.o signalpipe.o socket.o |
| + | DHCPD_OBJS = dhcpd.o arpping.o files.o leases.o serverpacket.o static_leases.o |
| + | DHCPC_OBJS = dhcpc.o clientpacket.o clientsocket.o script.o |
| + | |
| + | ifdef COMBINED_BINARY |
| + | EXEC1 = udhcpd |
| + | OBJS1 = $(DHCPD_OBJS) $(DHCPC_OBJS) $(OBJS_SHARED) frontend.o |
| + | CFLAGS += -DCOMBINED_BINARY |
| + | else |
| + | EXEC1 = udhcpd |
| + | OBJS1 = $(DHCPD_OBJS) $(OBJS_SHARED) |
| + | |
| + | EXEC2 = udhcpc |
| + | OBJS2 = $(DHCPC_OBJS) $(OBJS_SHARED) |
| + | endif |
| + | |
| + | EXEC3 = dumpleases |
| + | OBJS3 = dumpleases.o |
| + | |
| + | BOOT_PROGRAM = udhcpc |
| + | DAEMON = udhcpd |
| + | COMMAND = dumpleases |
| + | |
| + | ifdef UDHCP_SYSLOG |
| + | CFLAGS += -DUDHCP_SYSLOG |
| + | endif |
| + | |
| + | CFLAGS += -W -Wall -Wstrict-prototypes -D_GNU_SOURCE |
| + | |
| + | ifdef UDHCP_DEBUG |
| + | CFLAGS += -g -DUDHCP_DEBUG |
| + | STRIP=true |
| + | else |
| + | CFLAGS += -Os -fomit-frame-pointer |
| + | STRIP=$(CROSS_COMPILE)strip |
| + | endif |
| + | |
| + | all: $(EXEC1) $(EXEC2) $(EXEC3) |
| + | $(STRIP) --remove-section=.note --remove-section=.comment $(EXEC1) $(EXEC2) $(EXEC3) |
| + | |
| + | $(OBJS1) $(OBJS2) $(OBJS3): *.h Makefile |
| + | $(EXEC1) $(EXEC2) $(EXEC3): Makefile |
| + | |
| + | .c.o: |
| + | $(CC) -c $(CFLAGS) $< |
| + | |
| + | $(EXEC1): $(OBJS1) |
| + | $(LD) $(CFLAGS) $(LDFLAGS) $(OBJS1) -o $(EXEC1) |
| + | |
| + | $(EXEC2): $(OBJS2) |
| + | $(LD) $(CFLAGS) $(LDFLAGS) $(OBJS2) -o $(EXEC2) |
| + | |
| + | $(EXEC3): $(OBJS3) |
| + | $(LD) $(CFLAGS) $(LDFLAGS) $(OBJS3) -o $(EXEC3) |
| + | |
| + | |
| + | install: all |
| + | mkdir -p $(USRSBINDIR) $(USRBINDIR) |
| + | $(INSTALL) -m 755 $(DAEMON) $(USRSBINDIR) |
| + | $(INSTALL) -m 755 $(COMMAND) $(USRBINDIR) |
| + | ifdef COMBINED_BINARY |
| + | ln -sf $(DAEMON) $(USRSBINDIR)/$(BOOT_PROGRAM) |
| + | else |
| + | $(INSTALL) -m 755 $(BOOT_PROGRAM) $(USRSBINDIR) |
| + | endif |
| + | mkdir -p $(USRSHAREDIR)/udhcpc |
| + | for name in bound deconfig nak renew script ; do \ |
| + | $(INSTALL) -m 755 samples/sample.$$name \ |
| + | $(USRSHAREDIR)/udhcpc/default.$$name ; \ |
| + | done |
| + | mkdir -p $(USRSHAREDIR)/man/man1 |
| + | $(INSTALL) -m 644 dumpleases.1 $(USRSHAREDIR)/man/man1 |
| + | mkdir -p $(USRSHAREDIR)/man/man5 |
| + | $(INSTALL) -m 644 udhcpd.conf.5 $(USRSHAREDIR)/man/man5 |
| + | mkdir -p $(USRSHAREDIR)/man/man8 |
| + | $(INSTALL) -m 644 udhcpc.8 udhcpd.8 $(USRSHAREDIR)/man/man8 |
| + | |
| + | clean: |
| + | -rm -f udhcpd udhcpc dumpleases *.o *.a core |
| @@ -0,0 +1,53 @@ | |
| + | udhcp server/client package readme |
| + | ------------------------- |
| + | |
| + | The udhcp server/client package is primarily geared towards embedded |
| + | systems. It does however, strive to be fully functional, and RFC |
| + | compliant. |
| + | |
| + | |
| + | compile time options |
| + | ------------------- |
| + | |
| + | The Makefile contains three of the compile time options: |
| + | |
| + | UDHCP_DEBUG: If UDHCP_DEBUG is defined, udhcpd will output extra |
| + | debugging output, compile with -g, and not fork to the background when |
| + | run. |
| + | UDHCP_SYSLOG: If UDHCP_SYSLOG is defined, udhcpd will log all its |
| + | messages syslog, otherwise, it will attempt to log them to stdout. |
| + | |
| + | COMBINED_BINARY: If COMBINED_BINARY is define, one binary, udhcpd, |
| + | is created. If called as udhcpd, the dhcp server will be started. |
| + | If called as udhcpc, the dhcp client will be started. |
| + | |
| + | dhcpd.h contains the other three compile time options: |
| + | |
| + | LEASE_TIME: The default lease time if not specified in the config |
| + | file. |
| + | |
| + | LEASES_FILE: The default file for storing leases. |
| + | |
| + | DHCPD_CONFIG_FILE: The defualt config file to use. |
| + | |
| + | options.c contains a set of dhcp options for the client: |
| + | |
| + | name[10]: The name of the option as it will appear in scripts |
| + | |
| + | flags: The type of option, as well as if it will be requested |
| + | by the client (OPTION_REQ) |
| + | |
| + | code: The DHCP code for this option |
| + | |
| + | |
| + | busybox drop-in |
| + | -------------- |
| + | udhcp is now a drop-in component for busybox (http://busybox.net). |
| + | To update busybox to the latest revision, simply do a: |
| + | |
| + | cp *.[ch] README AUTHORS COPYING ChangeLog TODO \ |
| + | <busybox_source>/networking/udhcp |
| + | |
| + | The only two files udhcp does not provide are config.in and |
| + | Makefile.in, so these may need to be updated from time to time. |
| + | |
| @@ -0,0 +1,17 @@ | |
| + | udhcp lease dump (dumpleases) |
| + | ---------------------------- |
| + | |
| + | dumpleases displays the leases written out by the udhcpd server. Lease |
| + | times are stored in the file by time remaining in lease (for systems |
| + | without clock that works when there is no power), or by the absolute |
| + | time that it expires in seconds from epoch. dumpleases accepts the |
| + | following command line options: |
| + | |
| + | -a, --absolute Interpret lease times as expiration time. |
| + | -r, --remaining Interpret lease times as remaining time. |
| + | -f, --file=FILE Read lease information from FILE. |
| + | -h, --help Display help. |
| + | |
| + | Note that if udhcpd has not written a leases file recently, the output |
| + | of may not be up to date. |
| + | |
| @@ -0,0 +1,144 @@ | |
| + | udhcp client (udhcpc) |
| + | -------------------- |
| + | |
| + | The udhcp client negotiates a lease with the DHCP server and notifies |
| + | a set of scripts when a leases is obtained or lost. |
| + | |
| + | |
| + | command line options |
| + | ------------------- |
| + | |
| + | The command line options for the udhcp client are: |
| + | |
| + | -c, --clientid=CLIENTID Set client identifier. Type is first char. |
| + | -C, --clientid-none Suppress default client identifier |
| + | -V, --vendorclass=CLASSID Set vendor class identifier |
| + | -H, --hostname=HOSTNAME Client hostname |
| + | -h, Alias for -H |
| + | -F, --fqdn=FQDN Client fully qualified domain name |
| + | -f, --foreground Do not fork after getting lease |
| + | -b, --background Fork to background if lease cannot be |
| + | immediately negotiated. |
| + | -i, --interface=INTERFACE Interface to use (default: eth0) |
| + | -n, --now Exit with failure if lease cannot be |
| + | immediately negotiated. |
| + | -p, --pidfile=file Store process ID of daemon in file |
| + | -q, --quit Quit after obtaining lease |
| + | -r, --request=IP IP address to request (default: none) |
| + | -s, --script=file Run file at dhcp events (default: |
| + | /usr/share/udhcpc/default.script) |
| + | -v, --version Display version |
| + | |
| + | |
| + | If the requested IP address cannot be obtained, the client accepts the |
| + | address that the server offers. |
| + | |
| + | |
| + | udhcp client scripts |
| + | ------------------- |
| + | |
| + | When an event occurs, udhcpc calls the action script. udhcpc never does |
| + | any configuration of the network interface itself, but instead relies on |
| + | a set of scripts. The script by default is |
| + | /usr/share/udhcpc/default.script but this can be changed via the command |
| + | line arguments. The three possible arguments to the script are: |
| + | |
| + | deconfig: This argument is used when udhcpc starts, and |
| + | when a leases is lost. The script must put the interface in an |
| + | up, but deconfigured state, ie: ifconfig $interface 0.0.0.0. |
| + | |
| + | bound: This argument is used when udhcpc moves from an |
| + | unbound, to a bound state. All of the paramaters are set in |
| + | enviromental variables, The script should configure the interface, |
| + | and set any other relavent parameters (default gateway, dns server, |
| + | etc). |
| + | |
| + | renew: This argument is used when a DHCP lease is renewed. All of |
| + | the paramaters are set in enviromental variables. This argument is |
| + | used when the interface is already configured, so the IP address, |
| + | will not change, however, the other DHCP paramaters, such as the |
| + | default gateway, subnet mask, and dns server may change. |
| + | |
| + | nak: This argument is used with udhcpc receives a NAK message. |
| + | The script with the deconfig argument will be called directly |
| + | afterwards, so no changes to the network interface are neccessary. |
| + | This hook is provided for purely informational purposes (the |
| + | message option may contain a reason for the NAK). |
| + | |
| + | The paramaters for enviromental variables are as follows: |
| + | |
| + | $HOME - The set $HOME env or "/" |
| + | $PATH - the set $PATH env or "/bin:/usr/bin:/sbin:/usr/sbin" |
| + | $1 - What action the script should perform |
| + | interface - The interface this was obtained on |
| + | ip - The obtained IP |
| + | mask - The number of bits in the netmask (ie: 24) |
| + | siaddr - The bootp next server option |
| + | sname - The bootp server name option |
| + | boot_file - The bootp boot file option |
| + | subnet - The assigend subnet mask |
| + | timezone - Offset in seconds from UTC |
| + | router - A list of routers |
| + | timesvr - A list of time servers |
| + | namesvr - A list of IEN 116 name servers |
| + | dns - A list of DNS server |
| + | logsvr - A list of MIT-LCS UDP log servers |
| + | cookiesvr - A list of RFC 865 cookie servers |
| + | lprsvr - A list of LPR servers |
| + | hostname - The assigned hostname |
| + | bootsize - The length in 512 octect blocks of the bootfile |
| + | domain - The domain name of the network |
| + | swapsvr - The IP address of the client's swap server |
| + | rootpath - The path name of the client's root disk |
| + | ipttl - The TTL to use for this network |
| + | mtu - The MTU to use for this network |
| + | broadcast - The broadcast address for this network |
| + | ntpsrv - A list of NTP servers |
| + | wins - A list of WINS servers |
| + | lease - The lease time, in seconds |
| + | dhcptype - DHCP message type (safely ignored) |
| + | serverid - The IP of the server |
| + | message - Reason for a DHCPNAK |
| + | tftp - The TFTP server name |
| + | bootfile - The bootfile name |
| + | |
| + | additional options are easily added in options.c. |
| + | |
| + | |
| + | note on udhcpc's random seed |
| + | --------------------------- |
| + | |
| + | udhcpc will seed its random number generator (used for generating xid's) |
| + | by reading /dev/urandom. If you have a lot of embedded systems on the same |
| + | network, with no entropy, you can either seed /dev/urandom by a method of |
| + | your own, or doing the following on startup: |
| + | |
| + | ifconfig eth0 > /dev/urandom |
| + | |
| + | in order to seed /dev/urandom with some data (mac address) unique to your |
| + | system. If reading /dev/urandom fails, udhcpc will fall back to its old |
| + | behavior of seeding with time(0). |
| + | |
| + | |
| + | signals accepted by udhcpc |
| + | ------------------------- |
| + | |
| + | udhcpc also responds to SIGUSR1 and SIGUSR2. SIGUSR1 will force a renew state, |
| + | and SIGUSR2 will force a release of the current lease, and cause udhcpc to |
| + | go into an inactive state (until it is killed, or receives a SIGUSR1). You do |
| + | not need to sleep between sending signals, as signals received are processed |
| + | sequencially in the order they are received. |
| + | |
| + | |
| + | compile time options |
| + | ------------------- |
| + | |
| + | options.c contains a set of dhcp options for the client: |
| + | |
| + | name[10]: The name of the option as it will appear in scripts |
| + | |
| + | flags: The type of option, as well as if it will be requested |
| + | by the client (OPTION_REQ) |
| + | |
| + | code: The DHCP code for this option |
| + | |
| @@ -0,0 +1,59 @@ | |
| + | udhcp server (udhcpd) |
| + | -------------------- |
| + | |
| + | The only command line argument to udhcpd is an optional specifed |
| + | config file. If no config file is specified, udhcpd uses the default |
| + | config file, /etc/udhcpd.conf. Ex: |
| + | |
| + | udhcpd /etc/udhcpd.eth1.conf |
| + | |
| + | The udhcp server employs a number of simple config files: |
| + | |
| + | udhcpd.leases |
| + | ------------ |
| + | |
| + | The udhcpd.leases behavior is designed for an embedded system. The |
| + | file is written either every auto_time seconds, or when a SIGUSR1 |
| + | is received (the auto_time timer restarts if a SIGUSR1 is received). |
| + | If you send a SIGTERM to udhcpd directly after a SIGUSR1, udhcpd will |
| + | finish writing the leases file and wait for the aftermentioned script |
| + | to be executed and finish before quiting, so you do not need to sleep |
| + | between sending signals. When the file is written, a script can be |
| + | optionally called to commit the file to flash. Lease times are stored |
| + | in the file by time remaining in lease (for systems without clock |
| + | that works when there is no power), or by the absolute time that it |
| + | expires in seconds from epoch. In the remaining format, expired leases |
| + | are stored as zero. The file is of the format: |
| + | |
| + | 16 byte MAC |
| + | 4 byte ip address |
| + | u32 expire time |
| + | 16 byte MAC |
| + | 4 byte ip address |
| + | u32 expire time |
| + | . |
| + | etc. |
| + | |
| + | example: hexdump udhcpd.leases |
| + | |
| + | 0000000 1000 c95a 27d9 0000 0000 0000 0000 0000 |
| + | 0000010 a8c0 150a 0d00 2d29 5000 23fc 8566 0000 |
| + | 0000020 0000 0000 0000 0000 a8c0 140a 0d00 4e29 |
| + | 0000030 |
| + | |
| + | |
| + | udhcpd.conf |
| + | ---------- |
| + | |
| + | The format is fairly simple, there is a sample file with all the |
| + | available options and comments describing them in samples/udhcpd.conf |
| + | |
| + | compile time options |
| + | ------------------- |
| + | |
| + | dhcpd.h contains the other two compile time options: |
| + | |
| + | LEASE_TIME: The default lease time if not specified in the config |
| + | file. |
| + | |
| + | DHCPD_CONFIG_FILE: The defualt config file to use. |
| @@ -0,0 +1,16 @@ | |
| + | TODO |
| + | ---- |
| + | + Check for valid IP, netmask, hostname, paths, strings, etc |
| + | + Integrade README.*'s with manpages |
| + | + using time(0) breaks if the system clock changes, find a portable solution |
| + | + make failure of reading functions revert to previous value, not the default |
| + | + sanity code for option[OPT_LEN] |
| + | + fix aliasing (ie: eth0:0) |
| + | + better standard linux distro support |
| + | + make sure packet generation works on a wide varitey of arches |
| + | + Interoperability testing |
| + | + Hooks within the DHCP server |
| + | * Server notification when a lease is added/removed |
| + | + Additional bootp support in client/server |
| + | + Make serverid option in server configurable |
| + | + Possibly add failure message to DHCP NAK |
| @@ -0,0 +1,106 @@ | |
| + | /* |
| + | * arpping.c |
| + | * |
| + | * Mostly stolen from: dhcpcd - DHCP client daemon |
| + | * by Yoichi Hariguchi <[email protected]> |
| + | */ |
| + | |
| + | #include <sys/time.h> |
| + | #include <time.h> |
| + | #include <sys/socket.h> |
| + | #include <netinet/if_ether.h> |
| + | #include <net/if_arp.h> |
| + | #include <netinet/in.h> |
| + | #include <string.h> |
| + | #include <unistd.h> |
| + | #include <errno.h> |
| + | |
| + | #include "dhcpd.h" |
| + | #include "arpping.h" |
| + | #include "common.h" |
| + | |
| + | /* args: yiaddr - what IP to ping |
| + | * ip - our ip |
| + | * mac - our arp address |
| + | * interface - interface to use |
| + | * retn: 1 addr free |
| + | * 0 addr used |
| + | * -1 error |
| + | */ |
| + | |
| + | /* FIXME: match response against chaddr */ |
| + | int arpping(uint32_t yiaddr, uint32_t ip, uint8_t *mac, char *interface) |
| + | { |
| + | |
| + | int timeout = 2; |
| + | int optval = 1; |
| + | int s; /* socket */ |
| + | int rv = 1; /* return value */ |
| + | struct sockaddr addr; /* for interface name */ |
| + | struct arpMsg arp; |
| + | fd_set fdset; |
| + | struct timeval tm; |
| + | time_t prevTime; |
| + | |
| + | |
| + | if ((s = socket (PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP))) == -1) { |
| + | #ifdef IN_BUSYBOX |
| + | LOG(LOG_ERR, bb_msg_can_not_create_raw_socket); |
| + | #else |
| + | LOG(LOG_ERR, "Could not open raw socket"); |
| + | #endif |
| + | return -1; |
| + | } |
| + | |
| + | if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) { |
| + | LOG(LOG_ERR, "Could not setsocketopt on raw socket"); |
| + | close(s); |
| + | return -1; |
| + | } |
| + | |
| + | /* send arp request */ |
| + | memset(&arp, 0, sizeof(arp)); |
| + | memcpy(arp.h_dest, MAC_BCAST_ADDR, 6); /* MAC DA */ |
| + | memcpy(arp.h_source, mac, 6); /* MAC SA */ |
| + | arp.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */ |
| + | arp.htype = htons(ARPHRD_ETHER); /* hardware type */ |
| + | arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */ |
| + | arp.hlen = 6; /* hardware address length */ |
| + | arp.plen = 4; /* protocol address length */ |
| + | arp.operation = htons(ARPOP_REQUEST); /* ARP op code */ |
| + | memcpy(arp.sInaddr, &ip, sizeof(ip)); /* source IP address */ |
| + | memcpy(arp.sHaddr, mac, 6); /* source hardware address */ |
| + | memcpy(arp.tInaddr, &yiaddr, sizeof(yiaddr)); /* target IP address */ |
| + | |
| + | memset(&addr, 0, sizeof(addr)); |
| + | strcpy(addr.sa_data, interface); |
| + | if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) |
| + | rv = 0; |
| + | |
| + | /* wait arp reply, and check it */ |
| + | tm.tv_usec = 0; |
| + | prevTime = uptime(); |
| + | while (timeout > 0) { |
| + | FD_ZERO(&fdset); |
| + | FD_SET(s, &fdset); |
| + | tm.tv_sec = timeout; |
| + | if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0) { |
| + | DEBUG(LOG_ERR, "Error on ARPING request: %m"); |
| + | if (errno != EINTR) rv = 0; |
| + | } else if (FD_ISSET(s, &fdset)) { |
| + | if (recv(s, &arp, sizeof(arp), 0) < 0 ) rv = 0; |
| + | if (arp.operation == htons(ARPOP_REPLY) && |
| + | memcmp(arp.tHaddr, mac, 6) == 0 && |
| + | *((uint32_t *) arp.sInaddr) == yiaddr) { |
| + | DEBUG(LOG_INFO, "Valid arp reply receved for this address"); |
| + | rv = 0; |
| + | break; |
| + | } |
| + | } |
| + | timeout -= uptime() - prevTime; |
| + | prevTime = uptime(); |
| + | } |
| + | close(s); |
| + | DEBUG(LOG_INFO, "%salid arp replies for this address", rv ? "No v" : "V"); |
| + | return rv; |
| + | } |
| @@ -0,0 +1,35 @@ | |
| + | /* |
| + | * arpping .h |
| + | */ |
| + | |
| + | #ifndef ARPPING_H |
| + | #define ARPPING_H |
| + | |
| + | #include <netinet/if_ether.h> |
| + | #include <net/if_arp.h> |
| + | #include <net/if.h> |
| + | #include <netinet/in.h> |
| + | |
| + | struct arpMsg { |
| + | /* Ethernet header */ |
| + | u_char h_dest[6]; /* destination ether addr */ |
| + | u_char h_source[6]; /* source ether addr */ |
| + | u_short h_proto; /* packet type ID field */ |
| + | |
| + | /* ARP packet */ |
| + | uint16_t htype; /* hardware type (must be ARPHRD_ETHER) */ |
| + | uint16_t ptype; /* protocol type (must be ETH_P_IP) */ |
| + | uint8_t hlen; /* hardware address length (must be 6) */ |
| + | uint8_t plen; /* protocol address length (must be 4) */ |
| + | uint16_t operation; /* ARP opcode */ |
| + | uint8_t sHaddr[6]; /* sender's hardware address */ |
| + | uint8_t sInaddr[4]; /* sender's IP address */ |
| + | uint8_t tHaddr[6]; /* target's hardware address */ |
| + | uint8_t tInaddr[4]; /* target's IP address */ |
| + | uint8_t pad[18]; /* pad for min. Ethernet payload (60 bytes) */ |
| + | } ATTRIBUTE_PACKED; |
| + | |
| + | /* function prototypes */ |
| + | int arpping(uint32_t yiaddr, uint32_t ip, uint8_t *arp, char *interface); |
| + | |
| + | #endif |
| @@ -0,0 +1,245 @@ | |
| + | /* clientpacket.c |
| + | * |
| + | * Packet generation and dispatching functions for the DHCP client. |
| + | * |
| + | * Russ Dill <[email protected]> July 2001 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | #include <string.h> |
| + | #include <sys/socket.h> |
| + | #include <features.h> |
| + | #if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION |
| + | #include <netpacket/packet.h> |
| + | #include <net/ethernet.h> |
| + | #else |
| + | #include <asm/types.h> |
| + | #include <linux/if_packet.h> |
| + | #include <linux/if_ether.h> |
| + | #endif |
| + | #include <stdlib.h> |
| + | #include <time.h> |
| + | #include <unistd.h> |
| + | #include <netinet/in.h> |
| + | #include <arpa/inet.h> |
| + | #include <fcntl.h> |
| + | |
| + | |
| + | #include "dhcpd.h" |
| + | #include "clientpacket.h" |
| + | #include "options.h" |
| + | #include "dhcpc.h" |
| + | #include "common.h" |
| + | |
| + | |
| + | /* Create a random xid */ |
| + | unsigned long random_xid(void) |
| + | { |
| + | static int initialized; |
| + | if (!initialized) { |
| + | int fd; |
| + | unsigned long seed; |
| + | |
| + | fd = open("/dev/urandom", 0); |
| + | if (fd < 0 || read(fd, &seed, sizeof(seed)) < 0) { |
| + | LOG(LOG_WARNING, "Could not load seed from /dev/urandom: %m"); |
| + | seed = time(0); |
| + | } |
| + | if (fd >= 0) close(fd); |
| + | srand(seed); |
| + | initialized++; |
| + | } |
| + | return rand(); |
| + | } |
| + | |
| + | |
| + | /* initialize a packet with the proper defaults */ |
| + | static void init_packet(struct dhcpMessage *packet, char type) |
| + | { |
| + | init_header(packet, type); |
| + | memcpy(packet->chaddr, client_config.arp, 6); |
| + | if (client_config.clientid) |
| + | add_option_string(packet->options, client_config.clientid); |
| + | if (client_config.hostname) add_option_string(packet->options, client_config.hostname); |
| + | if (client_config.fqdn) add_option_string(packet->options, client_config.fqdn); |
| + | add_option_string(packet->options, client_config.vendorclass); |
| + | } |
| + | |
| + | |
| + | /* Add a parameter request list for stubborn DHCP servers. Pull the data |
| + | * from the struct in options.c. Don't do bounds checking here because it |
| + | * goes towards the head of the packet. */ |
| + | static void add_requests(struct dhcpMessage *packet) |
| + | { |
| + | int end = end_option(packet->options); |
| + | int i, len = 0; |
| + | |
| + | packet->options[end + OPT_CODE] = DHCP_PARAM_REQ; |
| + | for (i = 0; dhcp_options[i].code; i++) |
| + | if (dhcp_options[i].flags & OPTION_REQ) |
| + | packet->options[end + OPT_DATA + len++] = dhcp_options[i].code; |
| + | packet->options[end + OPT_LEN] = len; |
| + | packet->options[end + OPT_DATA + len] = DHCP_END; |
| + | |
| + | } |
| + | |
| + | |
| + | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ |
| + | int send_discover(unsigned long xid, unsigned long requested) |
| + | { |
| + | struct dhcpMessage packet; |
| + | |
| + | init_packet(&packet, DHCPDISCOVER); |
| + | packet.xid = xid; |
| + | if (requested) |
| + | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); |
| + | |
| + | add_requests(&packet); |
| + | LOG(LOG_DEBUG, "Sending discover..."); |
| + | return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, |
| + | SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); |
| + | } |
| + | |
| + | |
| + | /* Broadcasts a DHCP request message */ |
| + | int send_selecting(unsigned long xid, unsigned long server, unsigned long requested) |
| + | { |
| + | struct dhcpMessage packet; |
| + | struct in_addr addr; |
| + | |
| + | init_packet(&packet, DHCPREQUEST); |
| + | packet.xid = xid; |
| + | |
| + | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); |
| + | add_simple_option(packet.options, DHCP_SERVER_ID, server); |
| + | |
| + | add_requests(&packet); |
| + | addr.s_addr = requested; |
| + | LOG(LOG_DEBUG, "Sending select for %s...", inet_ntoa(addr)); |
| + | return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, |
| + | SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); |
| + | } |
| + | |
| + | |
| + | /* Unicasts or broadcasts a DHCP renew message */ |
| + | int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr) |
| + | { |
| + | struct dhcpMessage packet; |
| + | int ret = 0; |
| + | |
| + | init_packet(&packet, DHCPREQUEST); |
| + | packet.xid = xid; |
| + | packet.ciaddr = ciaddr; |
| + | |
| + | add_requests(&packet); |
| + | LOG(LOG_DEBUG, "Sending renew..."); |
| + | if (server) |
| + | ret = kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); |
| + | else ret = raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, |
| + | SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); |
| + | return ret; |
| + | } |
| + | |
| + | |
| + | /* Unicasts a DHCP release message */ |
| + | int send_release(unsigned long server, unsigned long ciaddr) |
| + | { |
| + | struct dhcpMessage packet; |
| + | |
| + | init_packet(&packet, DHCPRELEASE); |
| + | packet.xid = random_xid(); |
| + | packet.ciaddr = ciaddr; |
| + | |
| + | add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr); |
| + | add_simple_option(packet.options, DHCP_SERVER_ID, server); |
| + | |
| + | LOG(LOG_DEBUG, "Sending release..."); |
| + | return kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); |
| + | } |
| + | |
| + | |
| + | /* return -1 on errors that are fatal for the socket, -2 for those that aren't */ |
| + | int get_raw_packet(struct dhcpMessage *payload, int fd) |
| + | { |
| + | int bytes; |
| + | struct udp_dhcp_packet packet; |
| + | uint32_t source, dest; |
| + | uint16_t check; |
| + | |
| + | memset(&packet, 0, sizeof(struct udp_dhcp_packet)); |
| + | bytes = read(fd, &packet, sizeof(struct udp_dhcp_packet)); |
| + | if (bytes < 0) { |
| + | DEBUG(LOG_INFO, "couldn't read on raw listening socket -- ignoring"); |
| + | usleep(500000); /* possible down interface, looping condition */ |
| + | return -1; |
| + | } |
| + | |
| + | if (bytes < (int) (sizeof(struct iphdr) + sizeof(struct udphdr))) { |
| + | DEBUG(LOG_INFO, "message too short, ignoring"); |
| + | return -2; |
| + | } |
| + | |
| + | if (bytes < ntohs(packet.ip.tot_len)) { |
| + | DEBUG(LOG_INFO, "Truncated packet"); |
| + | return -2; |
| + | } |
| + | |
| + | /* ignore any extra garbage bytes */ |
| + | bytes = ntohs(packet.ip.tot_len); |
| + | |
| + | /* Make sure its the right packet for us, and that it passes sanity checks */ |
| + | if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION || |
| + | packet.ip.ihl != sizeof(packet.ip) >> 2 || packet.udp.dest != htons(CLIENT_PORT) || |
| + | bytes > (int) sizeof(struct udp_dhcp_packet) || |
| + | ntohs(packet.udp.len) != (uint16_t) (bytes - sizeof(packet.ip))) { |
| + | DEBUG(LOG_INFO, "unrelated/bogus packet"); |
| + | return -2; |
| + | } |
| + | |
| + | /* check IP checksum */ |
| + | check = packet.ip.check; |
| + | packet.ip.check = 0; |
| + | if (check != checksum(&(packet.ip), sizeof(packet.ip))) { |
| + | DEBUG(LOG_INFO, "bad IP header checksum, ignoring"); |
| + | return -1; |
| + | } |
| + | |
| + | /* verify the UDP checksum by replacing the header with a psuedo header */ |
| + | source = packet.ip.saddr; |
| + | dest = packet.ip.daddr; |
| + | check = packet.udp.check; |
| + | packet.udp.check = 0; |
| + | memset(&packet.ip, 0, sizeof(packet.ip)); |
| + | |
| + | packet.ip.protocol = IPPROTO_UDP; |
| + | packet.ip.saddr = source; |
| + | packet.ip.daddr = dest; |
| + | packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */ |
| + | if (check && check != checksum(&packet, bytes)) { |
| + | DEBUG(LOG_ERR, "packet with bad UDP checksum received, ignoring"); |
| + | return -2; |
| + | } |
| + | |
| + | memcpy(payload, &(packet.data), bytes - (sizeof(packet.ip) + sizeof(packet.udp))); |
| + | |
| + | if (ntohl(payload->cookie) != DHCP_MAGIC) { |
| + | LOG(LOG_ERR, "received bogus message (bad magic) -- ignoring"); |
| + | return -2; |
| + | } |
| + | DEBUG(LOG_INFO, "oooooh!!! got some!"); |
| + | return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); |
| + | |
| + | } |
| @@ -0,0 +1,14 @@ | |
| + | #ifndef _CLIENTPACKET_H |
| + | #define _CLIENTPACKET_H |
| + | |
| + | #include "packet.h" |
| + | |
| + | unsigned long random_xid(void); |
| + | int send_discover(unsigned long xid, unsigned long requested); |
| + | int send_selecting(unsigned long xid, unsigned long server, unsigned long requested); |
| + | int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr); |
| + | int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr); |
| + | int send_release(unsigned long server, unsigned long ciaddr); |
| + | int get_raw_packet(struct dhcpMessage *payload, int fd); |
| + | |
| + | #endif |
| @@ -0,0 +1,62 @@ | |
| + | /* |
| + | * clientsocket.c -- DHCP client socket creation |
| + | * |
| + | * udhcp client |
| + | * |
| + | * Russ Dill <[email protected]> July 2001 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | #include <sys/types.h> |
| + | #include <sys/socket.h> |
| + | #include <unistd.h> |
| + | #include <netinet/in.h> |
| + | #include <features.h> |
| + | #if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION |
| + | #include <netpacket/packet.h> |
| + | #include <net/ethernet.h> |
| + | #else |
| + | #include <asm/types.h> |
| + | #include <linux/if_packet.h> |
| + | #include <linux/if_ether.h> |
| + | #endif |
| + | |
| + | #include "clientsocket.h" |
| + | #include "common.h" |
| + | |
| + | |
| + | int raw_socket(int ifindex) |
| + | { |
| + | int fd; |
| + | struct sockaddr_ll sock; |
| + | |
| + | DEBUG(LOG_INFO, "Opening raw socket on ifindex %d", ifindex); |
| + | if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { |
| + | DEBUG(LOG_ERR, "socket call failed: %m"); |
| + | return -1; |
| + | } |
| + | |
| + | sock.sll_family = AF_PACKET; |
| + | sock.sll_protocol = htons(ETH_P_IP); |
| + | sock.sll_ifindex = ifindex; |
| + | if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) { |
| + | DEBUG(LOG_ERR, "bind call failed: %m"); |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | |
| + | return fd; |
| + | } |
| @@ -0,0 +1,7 @@ | |
| + | /* clientsocket.h */ |
| + | #ifndef _CLIENTSOCKET_H |
| + | #define _CLIENTSOCKET_H |
| + | |
| + | int raw_socket(int ifindex); |
| + | |
| + | #endif |
| @@ -0,0 +1,135 @@ | |
| + | /* vi: set sw=4 ts=4: */ |
| + | /* common.c |
| + | * |
| + | * Functions for debugging and logging as well as some other |
| + | * simple helper functions. |
| + | * |
| + | * Russ Dill <[email protected]> 2001-2003 |
| + | * Rewritten by Vladimir Oleynik <[email protected]> (C) 2003 |
| + | * |
| + | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| + | */ |
| + | |
| + | #include <fcntl.h> |
| + | #include <unistd.h> |
| + | #include <errno.h> |
| + | #include <string.h> |
| + | #include <stdlib.h> |
| + | #include <signal.h> |
| + | #include <paths.h> |
| + | #include <sys/socket.h> |
| + | #include <stdarg.h> |
| + | |
| + | #include "common.h" |
| + | #include "pidfile.h" |
| + | |
| + | |
| + | static int daemonized; |
| + | |
| + | long uptime(void) |
| + | { |
| + | struct sysinfo info; |
| + | sysinfo(&info); |
| + | return info.uptime; |
| + | } |
| + | |
| + | |
| + | /* |
| + | * This function makes sure our first socket calls |
| + | * aren't going to fd 1 (printf badness...) and are |
| + | * not later closed by daemon() |
| + | */ |
| + | static inline void sanitize_fds(void) |
| + | { |
| + | int zero; |
| + | if ((zero = open(_PATH_DEVNULL, O_RDWR, 0)) < 0) return; |
| + | while (zero < 3) zero = dup(zero); |
| + | close(zero); |
| + | } |
| + | |
| + | |
| + | void background(const char *pidfile) |
| + | { |
| + | #ifdef __uClinux__ |
| + | LOG(LOG_ERR, "Cannot background in uclinux (yet)"); |
| + | #else /* __uClinux__ */ |
| + | int pid_fd; |
| + | |
| + | /* hold lock during fork. */ |
| + | pid_fd = pidfile_acquire(pidfile); |
| + | if (daemon(0, 0) == -1) { /* bb_xdaemon? */ |
| + | perror("fork"); |
| + | exit(1); |
| + | } |
| + | daemonized++; |
| + | pidfile_write_release(pid_fd); |
| + | #endif /* __uClinux__ */ |
| + | } |
| + | |
| + | |
| + | #ifdef UDHCP_SYSLOG |
| + | |
| + | void udhcp_logging(int level, const char *fmt, ...) |
| + | { |
| + | va_list p; |
| + | va_list p2; |
| + | |
| + | va_start(p, fmt); |
| + | __va_copy(p2, p); |
| + | if(!daemonized) { |
| + | vprintf(fmt, p); |
| + | putchar('\n'); |
| + | } |
| + | vsyslog(level, fmt, p2); |
| + | va_end(p); |
| + | } |
| + | |
| + | #else |
| + | |
| + | |
| + | static char *syslog_level_msg[] = { |
| + | [LOG_EMERG] = "EMERGENCY!", |
| + | [LOG_ALERT] = "ALERT!", |
| + | [LOG_CRIT] = "critical!", |
| + | [LOG_WARNING] = "warning", |
| + | [LOG_ERR] = "error", |
| + | [LOG_INFO] = "info", |
| + | [LOG_DEBUG] = "debug" |
| + | }; |
| + | |
| + | |
| + | void udhcp_logging(int level, const char *fmt, ...) |
| + | { |
| + | va_list p; |
| + | |
| + | va_start(p, fmt); |
| + | if(!daemonized) { |
| + | printf("%s, ", syslog_level_msg[level]); |
| + | vprintf(fmt, p); |
| + | putchar('\n'); |
| + | } |
| + | va_end(p); |
| + | } |
| + | #endif |
| + | |
| + | |
| + | void start_log_and_pid(const char *client_server, const char *pidfile) |
| + | { |
| + | int pid_fd; |
| + | |
| + | /* Make sure our syslog fd isn't overwritten */ |
| + | sanitize_fds(); |
| + | |
| + | /* do some other misc startup stuff while we are here to save bytes */ |
| + | pid_fd = pidfile_acquire(pidfile); |
| + | pidfile_write_release(pid_fd); |
| + | |
| + | /* equivelent of doing a fflush after every \n */ |
| + | setlinebuf(stdout); |
| + | |
| + | #ifdef UDHCP_SYSLOG |
| + | openlog(client_server, LOG_PID | LOG_CONS, LOG_LOCAL0); |
| + | #endif |
| + | |
| + | udhcp_logging(LOG_INFO, "%s (v%s) started", client_server, VERSION); |
| + | } |
| @@ -0,0 +1,55 @@ | |
| + | /* common.h |
| + | * |
| + | * Russ Dill <[email protected]> September 2001 |
| + | * Rewritten by Vladimir Oleynik <[email protected]> (C) 2003 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | #ifndef _COMMON_H |
| + | #define _COMMON_H |
| + | |
| + | #include "version.h" |
| + | #include "libbb_udhcp.h" |
| + | |
| + | |
| + | #ifndef UDHCP_SYSLOG |
| + | enum syslog_levels { |
| + | LOG_EMERG = 0, |
| + | LOG_ALERT, |
| + | LOG_CRIT, |
| + | LOG_WARNING, |
| + | LOG_ERR, |
| + | LOG_INFO, |
| + | LOG_DEBUG |
| + | }; |
| + | #else |
| + | #include <syslog.h> |
| + | #endif |
| + | |
| + | long uptime(void); |
| + | void background(const char *pidfile); |
| + | void start_log_and_pid(const char *client_server, const char *pidfile); |
| + | void udhcp_logging(int level, const char *fmt, ...); |
| + | |
| + | #define LOG(level, str, args...) udhcp_logging(level, str, ## args) |
| + | |
| + | #ifdef UDHCP_DEBUG |
| + | # define DEBUG(level, str, args...) LOG(level, str, ## args) |
| + | #else |
| + | # define DEBUG(level, str, args...) do {;} while(0) |
| + | #endif |
| + | |
| + | #endif |
| @@ -0,0 +1,574 @@ | |
| + | /* dhcpc.c |
| + | * |
| + | * udhcp DHCP client |
| + | * |
| + | * Russ Dill <[email protected]> July 2001 |
| + | * |
| + | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
| + | */ |
| + | |
| + | #include <sys/time.h> |
| + | #include <sys/file.h> |
| + | #include <unistd.h> |
| + | #include <getopt.h> |
| + | #include <stdlib.h> |
| + | #include <sys/socket.h> |
| + | #include <netinet/in.h> |
| + | #include <arpa/inet.h> |
| + | #include <signal.h> |
| + | #include <time.h> |
| + | #include <string.h> |
| + | #include <sys/ioctl.h> |
| + | #include <net/if.h> |
| + | #include <errno.h> |
| + | |
| + | #include "common.h" |
| + | #include "dhcpd.h" |
| + | #include "dhcpc.h" |
| + | #include "options.h" |
| + | #include "clientpacket.h" |
| + | #include "clientsocket.h" |
| + | #include "script.h" |
| + | #include "socket.h" |
| + | #include "signalpipe.h" |
| + | |
| + | static int state; |
| + | static unsigned long requested_ip; /* = 0 */ |
| + | static unsigned long server_addr; |
| + | static unsigned long timeout; |
| + | static int packet_num; /* = 0 */ |
| + | static int fd = -1; |
| + | |
| + | #define LISTEN_NONE 0 |
| + | #define LISTEN_KERNEL 1 |
| + | #define LISTEN_RAW 2 |
| + | static int listen_mode; |
| + | |
| + | struct client_config_t client_config = { |
| + | /* Default options. */ |
| + | .abort_if_no_lease = 0, |
| + | .foreground = 0, |
| + | .quit_after_lease = 0, |
| + | .background_if_no_lease = 0, |
| + | .interface = "eth0", |
| + | .pidfile = NULL, |
| + | .script = DEFAULT_SCRIPT, |
| + | .clientid = NULL, |
| + | .vendorclass = NULL, |
| + | .hostname = NULL, |
| + | .fqdn = NULL, |
| + | .ifindex = 0, |
| + | .retries = 3, |
| + | .timeout = 3, |
| + | .arp = "\0\0\0\0\0\0", /* appease gcc-3.0 */ |
| + | }; |
| + | |
| + | #ifndef IN_BUSYBOX |
| + | static void ATTRIBUTE_NORETURN show_usage(void) |
| + | { |
| + | printf( |
| + | "Usage: udhcpc [OPTIONS]\n\n" |
| + | " -c, --clientid=CLIENTID Set client identifier - type is first char\n" |
| + | " -C, --clientid-none Suppress default client identifier\n" |
| + | " -V, --vendorclass=CLASSID Set vendor class identifier\n" |
| + | " -H, --hostname=HOSTNAME Client hostname\n" |
| + | " -h Alias for -H\n" |
| + | " -F, --fqdn=FQDN Client fully qualified domain name\n" |
| + | " -f, --foreground Do not fork after getting lease\n" |
| + | " -b, --background Fork to background if lease cannot be\n" |
| + | " immediately negotiated.\n" |
| + | " -i, --interface=INTERFACE Interface to use (default: eth0)\n" |
| + | " -n, --now Exit with failure if lease cannot be\n" |
| + | " immediately negotiated.\n" |
| + | " -p, --pidfile=file Store process ID of daemon in file\n" |
| + | " -q, --quit Quit after obtaining lease\n" |
| + | " -r, --request=IP IP address to request (default: none)\n" |
| + | " -s, --script=file Run file at dhcp events (default:\n" |
| + | " " DEFAULT_SCRIPT ")\n" |
| + | " -T, --timeout=seconds Try to get the lease for the amount of\n" |
| + | " seconds (default: 3)\n" |
| + | " -t, --retries=NUM Send up to NUM request packets\n" |
| + | " -v, --version Display version\n" |
| + | ); |
| + | exit(0); |
| + | } |
| + | #else |
| + | #define show_usage bb_show_usage |
| + | extern void show_usage(void) ATTRIBUTE_NORETURN; |
| + | #endif |
| + | |
| + | |
| + | /* just a little helper */ |
| + | static void change_mode(int new_mode) |
| + | { |
| + | DEBUG(LOG_INFO, "entering %s listen mode", |
| + | new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); |
| + | if (fd >= 0) close(fd); |
| + | fd = -1; |
| + | listen_mode = new_mode; |
| + | } |
| + | |
| + | |
| + | /* perform a renew */ |
| + | static void perform_renew(void) |
| + | { |
| + | LOG(LOG_INFO, "Performing a DHCP renew"); |
| + | switch (state) { |
| + | case BOUND: |
| + | change_mode(LISTEN_KERNEL); |
| + | case RENEWING: |
| + | case REBINDING: |
| + | state = RENEW_REQUESTED; |
| + | break; |
| + | case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ |
| + | run_script(NULL, "deconfig"); |
| + | case REQUESTING: |
| + | case RELEASED: |
| + | change_mode(LISTEN_RAW); |
| + | state = INIT_SELECTING; |
| + | break; |
| + | case INIT_SELECTING: |
| + | break; |
| + | } |
| + | |
| + | /* start things over */ |
| + | packet_num = 0; |
| + | |
| + | /* Kill any timeouts because the user wants this to hurry along */ |
| + | timeout = 0; |
| + | } |
| + | |
| + | |
| + | /* perform a release */ |
| + | static void perform_release(void) |
| + | { |
| + | char buffer[16]; |
| + | struct in_addr temp_addr; |
| + | |
| + | /* send release packet */ |
| + | if (state == BOUND || state == RENEWING || state == REBINDING) { |
| + | temp_addr.s_addr = server_addr; |
| + | sprintf(buffer, "%s", inet_ntoa(temp_addr)); |
| + | temp_addr.s_addr = requested_ip; |
| + | LOG(LOG_INFO, "Unicasting a release of %s to %s", |
| + | inet_ntoa(temp_addr), buffer); |
| + | send_release(server_addr, requested_ip); /* unicast */ |
| + | run_script(NULL, "deconfig"); |
| + | } |
| + | LOG(LOG_INFO, "Entering released state"); |
| + | |
| + | change_mode(LISTEN_NONE); |
| + | state = RELEASED; |
| + | timeout = 0x7fffffff; |
| + | } |
| + | |
| + | |
| + | static void client_background(void) |
| + | { |
| + | background(client_config.pidfile); |
| + | client_config.foreground = 1; /* Do not fork again. */ |
| + | client_config.background_if_no_lease = 0; |
| + | } |
| + | |
| + | |
| + | #ifdef COMBINED_BINARY |
| + | int udhcpc_main(int argc, char *argv[]) |
| + | #else |
| + | int main(int argc, char *argv[]) |
| + | #endif |
| + | { |
| + | uint8_t *temp, *message; |
| + | unsigned long t1 = 0, t2 = 0, xid = 0; |
| + | unsigned long start = 0, lease; |
| + | fd_set rfds; |
| + | int retval; |
| + | struct timeval tv; |
| + | int c, len; |
| + | struct dhcpMessage packet; |
| + | struct in_addr temp_addr; |
| + | long now; |
| + | int max_fd; |
| + | int sig; |
| + | int no_clientid = 0; |
| + | |
| + | static const struct option arg_options[] = { |
| + | {"clientid", required_argument, 0, 'c'}, |
| + | {"clientid-none", no_argument, 0, 'C'}, |
| + | {"vendorclass", required_argument, 0, 'V'}, |
| + | {"foreground", no_argument, 0, 'f'}, |
| + | {"background", no_argument, 0, 'b'}, |
| + | {"hostname", required_argument, 0, 'H'}, |
| + | {"hostname", required_argument, 0, 'h'}, |
| + | {"fqdn", required_argument, 0, 'F'}, |
| + | {"interface", required_argument, 0, 'i'}, |
| + | {"now", no_argument, 0, 'n'}, |
| + | {"pidfile", required_argument, 0, 'p'}, |
| + | {"quit", no_argument, 0, 'q'}, |
| + | {"request", required_argument, 0, 'r'}, |
| + | {"script", required_argument, 0, 's'}, |
| + | {"timeout", required_argument, 0, 'T'}, |
| + | {"version", no_argument, 0, 'v'}, |
| + | {"retries", required_argument, 0, 't'}, |
| + | {0, 0, 0, 0} |
| + | }; |
| + | |
| + | /* get options */ |
| + | while (1) { |
| + | int option_index = 0; |
| + | c = getopt_long(argc, argv, "c:CV:fbH:h:F:i:np:qr:s:T:t:v", arg_options, &option_index); |
| + | if (c == -1) break; |
| + | |
| + | switch (c) { |
| + | case 'c': |
| + | if (no_clientid) show_usage(); |
| + | len = strlen(optarg) > 255 ? 255 : strlen(optarg); |
| + | free(client_config.clientid); |
| + | client_config.clientid = xmalloc(len + 2); |
| + | client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; |
| + | client_config.clientid[OPT_LEN] = len; |
| + | client_config.clientid[OPT_DATA] = '\0'; |
| + | strncpy((char*)client_config.clientid + OPT_DATA, optarg, len); |
| + | break; |
| + | case 'C': |
| + | if (client_config.clientid) show_usage(); |
| + | no_clientid = 1; |
| + | break; |
| + | case 'V': |
| + | len = strlen(optarg) > 255 ? 255 : strlen(optarg); |
| + | free(client_config.vendorclass); |
| + | client_config.vendorclass = xmalloc(len + 2); |
| + | client_config.vendorclass[OPT_CODE] = DHCP_VENDOR; |
| + | client_config.vendorclass[OPT_LEN] = len; |
| + | strncpy((char*)client_config.vendorclass + OPT_DATA, optarg, len); |
| + | break; |
| + | case 'f': |
| + | client_config.foreground = 1; |
| + | break; |
| + | case 'b': |
| + | client_config.background_if_no_lease = 1; |
| + | break; |
| + | case 'h': |
| + | case 'H': |
| + | len = strlen(optarg) > 255 ? 255 : strlen(optarg); |
| + | free(client_config.hostname); |
| + | client_config.hostname = xmalloc(len + 2); |
| + | client_config.hostname[OPT_CODE] = DHCP_HOST_NAME; |
| + | client_config.hostname[OPT_LEN] = len; |
| + | strncpy((char*)client_config.hostname + 2, optarg, len); |
| + | break; |
| + | case 'F': |
| + | len = strlen(optarg) > 255 ? 255 : strlen(optarg); |
| + | free(client_config.fqdn); |
| + | client_config.fqdn = xmalloc(len + 5); |
| + | client_config.fqdn[OPT_CODE] = DHCP_FQDN; |
| + | client_config.fqdn[OPT_LEN] = len + 3; |
| + | /* Flags: 0000NEOS |
| + | S: 1 => Client requests Server to update A RR in DNS as well as PTR |
| + | O: 1 => Server indicates to client that DNS has been updated regardless |
| + | E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com" |
| + | N: 1 => Client requests Server to not update DNS |
| + | */ |
| + | client_config.fqdn[OPT_LEN + 1] = 0x1; |
| + | client_config.fqdn[OPT_LEN + 2] = 0; |
| + | client_config.fqdn[OPT_LEN + 3] = 0; |
| + | strncpy((char*)client_config.fqdn + 5, optarg, len); |
| + | break; |
| + | case 'i': |
| + | client_config.interface = optarg; |
| + | break; |
| + | case 'n': |
| + | client_config.abort_if_no_lease = 1; |
| + | break; |
| + | case 'p': |
| + | client_config.pidfile = optarg; |
| + | break; |
| + | case 'q': |
| + | client_config.quit_after_lease = 1; |
| + | break; |
| + | case 'r': |
| + | requested_ip = inet_addr(optarg); |
| + | break; |
| + | case 's': |
| + | client_config.script = optarg; |
| + | break; |
| + | case 'T': |
| + | client_config.timeout = atoi(optarg); |
| + | break; |
| + | case 't': |
| + | client_config.retries = atoi(optarg); |
| + | break; |
| + | case 'v': |
| + | printf("udhcpcd, version %s\n\n", VERSION); |
| + | return 0; |
| + | break; |
| + | default: |
| + | show_usage(); |
| + | } |
| + | } |
| + | |
| + | /* Start the log, sanitize fd's, and write a pid file */ |
| + | start_log_and_pid("udhcpc", client_config.pidfile); |
| + | |
| + | if (read_interface(client_config.interface, &client_config.ifindex, |
| + | NULL, client_config.arp) < 0) |
| + | return 1; |
| + | |
| + | /* if not set, and not suppressed, setup the default client ID */ |
| + | if (!client_config.clientid && !no_clientid) { |
| + | client_config.clientid = xmalloc(6 + 3); |
| + | client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; |
| + | client_config.clientid[OPT_LEN] = 7; |
| + | client_config.clientid[OPT_DATA] = 1; |
| + | memcpy(client_config.clientid + 3, client_config.arp, 6); |
| + | } |
| + | |
| + | if (!client_config.vendorclass) { |
| + | client_config.vendorclass = xmalloc(sizeof("udhcp "VERSION) + 2); |
| + | client_config.vendorclass[OPT_CODE] = DHCP_VENDOR; |
| + | client_config.vendorclass[OPT_LEN] = sizeof("udhcp "VERSION) - 1; |
| + | client_config.vendorclass[OPT_DATA] = 1; |
| + | memcpy(&client_config.vendorclass[OPT_DATA], |
| + | "udhcp "VERSION, sizeof("udhcp "VERSION) - 1); |
| + | } |
| + | |
| + | |
| + | /* setup the signal pipe */ |
| + | udhcp_sp_setup(); |
| + | |
| + | state = INIT_SELECTING; |
| + | run_script(NULL, "deconfig"); |
| + | change_mode(LISTEN_RAW); |
| + | |
| + | for (;;) { |
| + | |
| + | tv.tv_sec = timeout - uptime(); |
| + | tv.tv_usec = 0; |
| + | |
| + | if (listen_mode != LISTEN_NONE && fd < 0) { |
| + | if (listen_mode == LISTEN_KERNEL) |
| + | fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface); |
| + | else |
| + | fd = raw_socket(client_config.ifindex); |
| + | if (fd < 0) { |
| + | LOG(LOG_ERR, "FATAL: couldn't listen on socket, %m"); |
| + | return 0; |
| + | } |
| + | } |
| + | max_fd = udhcp_sp_fd_set(&rfds, fd); |
| + | |
| + | if (tv.tv_sec > 0) { |
| + | DEBUG(LOG_INFO, "Waiting on select..."); |
| + | retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); |
| + | } else retval = 0; /* If we already timed out, fall through */ |
| + | |
| + | now = uptime(); |
| + | if (retval == 0) { |
| + | /* timeout dropped to zero */ |
| + | switch (state) { |
| + | case INIT_SELECTING: |
| + | if (packet_num < client_config.retries) { |
| + | if (packet_num == 0) |
| + | xid = random_xid(); |
| + | |
| + | /* send discover packet */ |
| + | send_discover(xid, requested_ip); /* broadcast */ |
| + | |
| + | timeout = now + client_config.timeout; |
| + | packet_num++; |
| + | } else { |
| + | run_script(NULL, "leasefail"); |
| + | if (client_config.background_if_no_lease) { |
| + | LOG(LOG_INFO, "No lease, forking to background."); |
| + | client_background(); |
| + | } else if (client_config.abort_if_no_lease) { |
| + | LOG(LOG_INFO, "No lease, failing."); |
| + | return 1; |
| + | } |
| + | /* wait to try again */ |
| + | packet_num = 0; |
| + | timeout = now + 60; |
| + | } |
| + | break; |
| + | case RENEW_REQUESTED: |
| + | case REQUESTING: |
| + | if (packet_num < client_config.retries) { |
| + | /* send request packet */ |
| + | if (state == RENEW_REQUESTED) |
| + | send_renew(xid, server_addr, requested_ip); /* unicast */ |
| + | else send_selecting(xid, server_addr, requested_ip); /* broadcast */ |
| + | |
| + | timeout = now + ((packet_num == 2) ? 10 : 2); |
| + | packet_num++; |
| + | } else { |
| + | /* timed out, go back to init state */ |
| + | if (state == RENEW_REQUESTED) run_script(NULL, "deconfig"); |
| + | state = INIT_SELECTING; |
| + | timeout = now; |
| + | packet_num = 0; |
| + | change_mode(LISTEN_RAW); |
| + | } |
| + | break; |
| + | case BOUND: |
| + | /* Lease is starting to run out, time to enter renewing state */ |
| + | state = RENEWING; |
| + | change_mode(LISTEN_KERNEL); |
| + | DEBUG(LOG_INFO, "Entering renew state"); |
| + | /* fall right through */ |
| + | case RENEWING: |
| + | /* Either set a new T1, or enter REBINDING state */ |
| + | if ((t2 - t1) <= (lease / 14400 + 1)) { |
| + | /* timed out, enter rebinding state */ |
| + | state = REBINDING; |
| + | timeout = now + (t2 - t1); |
| + | DEBUG(LOG_INFO, "Entering rebinding state"); |
| + | } else { |
| + | /* send a request packet */ |
| + | send_renew(xid, server_addr, requested_ip); /* unicast */ |
| + | |
| + | t1 = (t2 - t1) / 2 + t1; |
| + | timeout = t1 + start; |
| + | } |
| + | break; |
| + | case REBINDING: |
| + | /* Either set a new T2, or enter INIT state */ |
| + | if ((lease - t2) <= (lease / 14400 + 1)) { |
| + | /* timed out, enter init state */ |
| + | state = INIT_SELECTING; |
| + | LOG(LOG_INFO, "Lease lost, entering init state"); |
| + | run_script(NULL, "deconfig"); |
| + | timeout = now; |
| + | packet_num = 0; |
| + | change_mode(LISTEN_RAW); |
| + | } else { |
| + | /* send a request packet */ |
| + | send_renew(xid, 0, requested_ip); /* broadcast */ |
| + | |
| + | t2 = (lease - t2) / 2 + t2; |
| + | timeout = t2 + start; |
| + | } |
| + | break; |
| + | case RELEASED: |
| + | /* yah, I know, *you* say it would never happen */ |
| + | timeout = 0x7fffffff; |
| + | break; |
| + | } |
| + | } else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) { |
| + | /* a packet is ready, read it */ |
| + | |
| + | if (listen_mode == LISTEN_KERNEL) |
| + | len = get_packet(&packet, fd); |
| + | else len = get_raw_packet(&packet, fd); |
| + | |
| + | if (len == -1 && errno != EINTR) { |
| + | DEBUG(LOG_INFO, "error on read, %m, reopening socket"); |
| + | change_mode(listen_mode); /* just close and reopen */ |
| + | } |
| + | if (len < 0) continue; |
| + | |
| + | if (packet.xid != xid) { |
| + | DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)", |
| + | (unsigned long) packet.xid, xid); |
| + | continue; |
| + | } |
| + | |
| + | /* Ignore packets that aren't for us */ |
| + | if (memcmp(packet.chaddr, client_config.arp, 6)) { |
| + | DEBUG(LOG_INFO, "packet does not have our chaddr -- ignoring"); |
| + | continue; |
| + | } |
| + | |
| + | if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { |
| + | DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring"); |
| + | continue; |
| + | } |
| + | |
| + | switch (state) { |
| + | case INIT_SELECTING: |
| + | /* Must be a DHCPOFFER to one of our xid's */ |
| + | if (*message == DHCPOFFER) { |
| + | if ((temp = get_option(&packet, DHCP_SERVER_ID))) { |
| + | memcpy(&server_addr, temp, 4); |
| + | xid = packet.xid; |
| + | requested_ip = packet.yiaddr; |
| + | |
| + | /* enter requesting state */ |
| + | state = REQUESTING; |
| + | timeout = now; |
| + | packet_num = 0; |
| + | } else { |
| + | DEBUG(LOG_ERR, "No server ID in message"); |
| + | } |
| + | } |
| + | break; |
| + | case RENEW_REQUESTED: |
| + | case REQUESTING: |
| + | case RENEWING: |
| + | case REBINDING: |
| + | if (*message == DHCPACK) { |
| + | if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) { |
| + | LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease"); |
| + | lease = 60 * 60; |
| + | } else { |
| + | memcpy(&lease, temp, 4); |
| + | lease = ntohl(lease); |
| + | } |
| + | |
| + | /* enter bound state */ |
| + | t1 = lease / 2; |
| + | |
| + | /* little fixed point for n * .875 */ |
| + | t2 = (lease * 0x7) >> 3; |
| + | temp_addr.s_addr = packet.yiaddr; |
| + | LOG(LOG_INFO, "Lease of %s obtained, lease time %ld", |
| + | inet_ntoa(temp_addr), lease); |
| + | start = now; |
| + | timeout = t1 + start; |
| + | requested_ip = packet.yiaddr; |
| + | run_script(&packet, |
| + | ((state == RENEWING || state == REBINDING) ? "renew" : "bound")); |
| + | |
| + | state = BOUND; |
| + | change_mode(LISTEN_NONE); |
| + | if (client_config.quit_after_lease) |
| + | return 0; |
| + | if (!client_config.foreground) |
| + | client_background(); |
| + | |
| + | } else if (*message == DHCPNAK) { |
| + | /* return to init state */ |
| + | LOG(LOG_INFO, "Received DHCP NAK"); |
| + | run_script(&packet, "nak"); |
| + | if (state != REQUESTING) |
| + | run_script(NULL, "deconfig"); |
| + | state = INIT_SELECTING; |
| + | timeout = now; |
| + | requested_ip = 0; |
| + | packet_num = 0; |
| + | change_mode(LISTEN_RAW); |
| + | sleep(3); /* avoid excessive network traffic */ |
| + | } |
| + | break; |
| + | /* case BOUND, RELEASED: - ignore all packets */ |
| + | } |
| + | } else if (retval > 0 && (sig = udhcp_sp_read(&rfds))) { |
| + | switch (sig) { |
| + | case SIGUSR1: |
| + | perform_renew(); |
| + | break; |
| + | case SIGUSR2: |
| + | perform_release(); |
| + | break; |
| + | case SIGTERM: |
| + | LOG(LOG_INFO, "Received SIGTERM"); |
| + | return 0; |
| + | } |
| + | } else if (retval == -1 && errno == EINTR) { |
| + | /* a signal was caught */ |
| + | } else { |
| + | /* An error occured */ |
| + | DEBUG(LOG_ERR, "Error on select"); |
| + | } |
| + | |
| + | } |
| + | return 0; |
| + | } |
| @@ -0,0 +1,39 @@ | |
| + | /* dhcpc.h */ |
| + | #ifndef _DHCPC_H |
| + | #define _DHCPC_H |
| + | |
| + | /* grab define DEFAULT_SCRIPT */ |
| + | #include "libbb_udhcp.h" |
| + | |
| + | #define INIT_SELECTING 0 |
| + | #define REQUESTING 1 |
| + | #define BOUND 2 |
| + | #define RENEWING 3 |
| + | #define REBINDING 4 |
| + | #define INIT_REBOOT 5 |
| + | #define RENEW_REQUESTED 6 |
| + | #define RELEASED 7 |
| + | |
| + | |
| + | struct client_config_t { |
| + | char foreground; /* Do not fork */ |
| + | char quit_after_lease; /* Quit after obtaining lease */ |
| + | char abort_if_no_lease; /* Abort if no lease */ |
| + | char background_if_no_lease; /* Fork to background if no lease */ |
| + | char *interface; /* The name of the interface to use */ |
| + | char *pidfile; /* Optionally store the process ID */ |
| + | char *script; /* User script to run at dhcp events */ |
| + | uint8_t *clientid; /* Optional client id to use */ |
| + | uint8_t *vendorclass; /* Optional vendor class-id to use */ |
| + | uint8_t *hostname; /* Optional hostname to use */ |
| + | uint8_t *fqdn; /* Optional fully qualified domain name to use */ |
| + | int ifindex; /* Index number of the interface to use */ |
| + | int retries; /* Max number of request packets */ |
| + | int timeout; /* Number of seconds to try to get a lease */ |
| + | uint8_t arp[6]; /* Our arp address */ |
| + | }; |
| + | |
| + | extern struct client_config_t client_config; |
| + | |
| + | |
| + | #endif |
| @@ -0,0 +1,273 @@ | |
| + | /* dhcpd.c |
| + | * |
| + | * udhcp Server |
| + | * Copyright (C) 1999 Matthew Ramsay <[email protected]> |
| + | * Chris Trew <[email protected]> |
| + | * |
| + | * Rewrite by Russ Dill <[email protected]> July 2001 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | #include <fcntl.h> |
| + | #include <string.h> |
| + | #include <stdlib.h> |
| + | #include <sys/wait.h> |
| + | #include <arpa/inet.h> |
| + | #include <netdb.h> |
| + | #include <netinet/in.h> |
| + | #include <sys/socket.h> |
| + | #include <unistd.h> |
| + | #include <signal.h> |
| + | #include <errno.h> |
| + | #include <sys/ioctl.h> |
| + | #include <time.h> |
| + | #include <sys/time.h> |
| + | |
| + | #include "dhcpd.h" |
| + | #include "arpping.h" |
| + | #include "socket.h" |
| + | #include "options.h" |
| + | #include "files.h" |
| + | #include "serverpacket.h" |
| + | #include "common.h" |
| + | #include "signalpipe.h" |
| + | #include "static_leases.h" |
| + | |
| + | |
| + | /* globals */ |
| + | struct dhcpOfferedAddr *leases; |
| + | struct server_config_t server_config; |
| + | |
| + | |
| + | #ifdef COMBINED_BINARY |
| + | int udhcpd_main(int argc, char *argv[]) |
| + | #else |
| + | int main(int argc, char *argv[]) |
| + | #endif |
| + | { |
| + | fd_set rfds; |
| + | struct timeval tv; |
| + | int server_socket = -1; |
| + | int bytes, retval; |
| + | struct dhcpMessage packet; |
| + | uint8_t *state; |
| + | uint8_t *server_id, *requested; |
| + | uint32_t server_id_align, requested_align; |
| + | unsigned long timeout_end; |
| + | struct option_set *option; |
| + | struct dhcpOfferedAddr *lease; |
| + | struct dhcpOfferedAddr static_lease; |
| + | int max_sock; |
| + | unsigned long num_ips; |
| + | |
| + | uint32_t static_lease_ip; |
| + | |
| + | memset(&server_config, 0, sizeof(struct server_config_t)); |
| + | read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]); |
| + | |
| + | /* Start the log, sanitize fd's, and write a pid file */ |
| + | start_log_and_pid("udhcpd", server_config.pidfile); |
| + | |
| + | if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) { |
| + | memcpy(&server_config.lease, option->data + 2, 4); |
| + | server_config.lease = ntohl(server_config.lease); |
| + | } |
| + | else server_config.lease = LEASE_TIME; |
| + | |
| + | /* Sanity check */ |
| + | num_ips = ntohl(server_config.end) - ntohl(server_config.start) + 1; |
| + | if (server_config.max_leases > num_ips) { |
| + | LOG(LOG_ERR, "max_leases value (%lu) not sane, " |
| + | "setting to %lu instead", |
| + | server_config.max_leases, num_ips); |
| + | server_config.max_leases = num_ips; |
| + | } |
| + | |
| + | leases = xcalloc(server_config.max_leases, sizeof(struct dhcpOfferedAddr)); |
| + | read_leases(server_config.lease_file); |
| + | |
| + | if (read_interface(server_config.interface, &server_config.ifindex, |
| + | &server_config.server, server_config.arp) < 0) |
| + | return 1; |
| + | |
| + | #ifndef UDHCP_DEBUG |
| + | background(server_config.pidfile); /* hold lock during fork. */ |
| + | #endif |
| + | |
| + | /* Setup the signal pipe */ |
| + | udhcp_sp_setup(); |
| + | |
| + | timeout_end = time(0) + server_config.auto_time; |
| + | while(1) { /* loop until universe collapses */ |
| + | |
| + | if (server_socket < 0) |
| + | if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) { |
| + | LOG(LOG_ERR, "FATAL: couldn't create server socket, %m"); |
| + | return 2; |
| + | } |
| + | |
| + | max_sock = udhcp_sp_fd_set(&rfds, server_socket); |
| + | if (server_config.auto_time) { |
| + | tv.tv_sec = timeout_end - time(0); |
| + | tv.tv_usec = 0; |
| + | } |
| + | if (!server_config.auto_time || tv.tv_sec > 0) { |
| + | retval = select(max_sock + 1, &rfds, NULL, NULL, |
| + | server_config.auto_time ? &tv : NULL); |
| + | } else retval = 0; /* If we already timed out, fall through */ |
| + | |
| + | if (retval == 0) { |
| + | write_leases(); |
| + | timeout_end = time(0) + server_config.auto_time; |
| + | continue; |
| + | } else if (retval < 0 && errno != EINTR) { |
| + | DEBUG(LOG_INFO, "error on select"); |
| + | continue; |
| + | } |
| + | |
| + | switch (udhcp_sp_read(&rfds)) { |
| + | case SIGUSR1: |
| + | LOG(LOG_INFO, "Received a SIGUSR1"); |
| + | write_leases(); |
| + | /* why not just reset the timeout, eh */ |
| + | timeout_end = time(0) + server_config.auto_time; |
| + | continue; |
| + | case SIGTERM: |
| + | LOG(LOG_INFO, "Received a SIGTERM"); |
| + | return 0; |
| + | case 0: break; /* no signal */ |
| + | default: continue; /* signal or error (probably EINTR) */ |
| + | } |
| + | |
| + | if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */ |
| + | if (bytes == -1 && errno != EINTR) { |
| + | DEBUG(LOG_INFO, "error on read, %m, reopening socket"); |
| + | close(server_socket); |
| + | server_socket = -1; |
| + | } |
| + | continue; |
| + | } |
| + | |
| + | if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { |
| + | DEBUG(LOG_ERR, "couldn't get option from packet, ignoring"); |
| + | continue; |
| + | } |
| + | |
| + | /* Look for a static lease */ |
| + | static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr); |
| + | |
| + | if(static_lease_ip) |
| + | { |
| + | printf("Found static lease: %x\n", static_lease_ip); |
| + | |
| + | memcpy(&static_lease.chaddr, &packet.chaddr, 16); |
| + | static_lease.yiaddr = static_lease_ip; |
| + | static_lease.expires = 0; |
| + | |
| + | lease = &static_lease; |
| + | |
| + | } |
| + | else |
| + | { |
| + | lease = find_lease_by_chaddr(packet.chaddr); |
| + | } |
| + | |
| + | switch (state[0]) { |
| + | case DHCPDISCOVER: |
| + | DEBUG(LOG_INFO,"received DISCOVER"); |
| + | |
| + | if (sendOffer(&packet) < 0) { |
| + | LOG(LOG_ERR, "send OFFER failed"); |
| + | } |
| + | break; |
| + | case DHCPREQUEST: |
| + | DEBUG(LOG_INFO, "received REQUEST"); |
| + | |
| + | requested = get_option(&packet, DHCP_REQUESTED_IP); |
| + | server_id = get_option(&packet, DHCP_SERVER_ID); |
| + | |
| + | if (requested) memcpy(&requested_align, requested, 4); |
| + | if (server_id) memcpy(&server_id_align, server_id, 4); |
| + | |
| + | if (lease) { |
| + | if (server_id) { |
| + | /* SELECTING State */ |
| + | DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align)); |
| + | if (server_id_align == server_config.server && requested && |
| + | requested_align == lease->yiaddr) { |
| + | sendACK(&packet, lease->yiaddr); |
| + | } |
| + | } else { |
| + | if (requested) { |
| + | /* INIT-REBOOT State */ |
| + | if (lease->yiaddr == requested_align) |
| + | sendACK(&packet, lease->yiaddr); |
| + | else sendNAK(&packet); |
| + | } else { |
| + | /* RENEWING or REBINDING State */ |
| + | if (lease->yiaddr == packet.ciaddr) |
| + | sendACK(&packet, lease->yiaddr); |
| + | else { |
| + | /* don't know what to do!!!! */ |
| + | sendNAK(&packet); |
| + | } |
| + | } |
| + | } |
| + | |
| + | /* what to do if we have no record of the client */ |
| + | } else if (server_id) { |
| + | /* SELECTING State */ |
| + | |
| + | } else if (requested) { |
| + | /* INIT-REBOOT State */ |
| + | if ((lease = find_lease_by_yiaddr(requested_align))) { |
| + | if (lease_expired(lease)) { |
| + | /* probably best if we drop this lease */ |
| + | memset(lease->chaddr, 0, 16); |
| + | /* make some contention for this address */ |
| + | } else sendNAK(&packet); |
| + | } else if (requested_align < server_config.start || |
| + | requested_align > server_config.end) { |
| + | sendNAK(&packet); |
| + | } /* else remain silent */ |
| + | |
| + | } else { |
| + | /* RENEWING or REBINDING State */ |
| + | } |
| + | break; |
| + | case DHCPDECLINE: |
| + | DEBUG(LOG_INFO,"received DECLINE"); |
| + | if (lease) { |
| + | memset(lease->chaddr, 0, 16); |
| + | lease->expires = time(0) + server_config.decline_time; |
| + | } |
| + | break; |
| + | case DHCPRELEASE: |
| + | DEBUG(LOG_INFO,"received RELEASE"); |
| + | if (lease) lease->expires = time(0); |
| + | break; |
| + | case DHCPINFORM: |
| + | DEBUG(LOG_INFO,"received INFORM"); |
| + | send_inform(&packet); |
| + | break; |
| + | default: |
| + | LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]); |
| + | } |
| + | } |
| + | |
| + | return 0; |
| + | } |
| + | |
| @@ -0,0 +1,141 @@ | |
| + | /* dhcpd.h */ |
| + | #ifndef _DHCPD_H |
| + | #define _DHCPD_H |
| + | |
| + | #include <netinet/ip.h> |
| + | #include <netinet/udp.h> |
| + | |
| + | #include "libbb_udhcp.h" |
| + | #include "leases.h" |
| + | #include "version.h" |
| + | |
| + | /************************************/ |
| + | /* Defaults _you_ may want to tweak */ |
| + | /************************************/ |
| + | |
| + | /* the period of time the client is allowed to use that address */ |
| + | #define LEASE_TIME (60*60*24*10) /* 10 days of seconds */ |
| + | #define LEASES_FILE "/var/lib/misc/udhcpd.leases" |
| + | |
| + | /* where to find the DHCP server configuration file */ |
| + | #define DHCPD_CONF_FILE "/etc/udhcpd.conf" |
| + | |
| + | /*****************************************************************/ |
| + | /* Do not modify below here unless you know what you are doing!! */ |
| + | /*****************************************************************/ |
| + | |
| + | /* DHCP protocol -- see RFC 2131 */ |
| + | #define SERVER_PORT 67 |
| + | #define CLIENT_PORT 68 |
| + | |
| + | #define DHCP_MAGIC 0x63825363 |
| + | |
| + | /* DHCP option codes (partial list) */ |
| + | #define DHCP_PADDING 0x00 |
| + | #define DHCP_SUBNET 0x01 |
| + | #define DHCP_TIME_OFFSET 0x02 |
| + | #define DHCP_ROUTER 0x03 |
| + | #define DHCP_TIME_SERVER 0x04 |
| + | #define DHCP_NAME_SERVER 0x05 |
| + | #define DHCP_DNS_SERVER 0x06 |
| + | #define DHCP_LOG_SERVER 0x07 |
| + | #define DHCP_COOKIE_SERVER 0x08 |
| + | #define DHCP_LPR_SERVER 0x09 |
| + | #define DHCP_HOST_NAME 0x0c |
| + | #define DHCP_BOOT_SIZE 0x0d |
| + | #define DHCP_DOMAIN_NAME 0x0f |
| + | #define DHCP_SWAP_SERVER 0x10 |
| + | #define DHCP_ROOT_PATH 0x11 |
| + | #define DHCP_IP_TTL 0x17 |
| + | #define DHCP_MTU 0x1a |
| + | #define DHCP_BROADCAST 0x1c |
| + | #define DHCP_NTP_SERVER 0x2a |
| + | #define DHCP_WINS_SERVER 0x2c |
| + | #define DHCP_REQUESTED_IP 0x32 |
| + | #define DHCP_LEASE_TIME 0x33 |
| + | #define DHCP_OPTION_OVER 0x34 |
| + | #define DHCP_MESSAGE_TYPE 0x35 |
| + | #define DHCP_SERVER_ID 0x36 |
| + | #define DHCP_PARAM_REQ 0x37 |
| + | #define DHCP_MESSAGE 0x38 |
| + | #define DHCP_MAX_SIZE 0x39 |
| + | #define DHCP_T1 0x3a |
| + | #define DHCP_T2 0x3b |
| + | #define DHCP_VENDOR 0x3c |
| + | #define DHCP_CLIENT_ID 0x3d |
| + | #define DHCP_FQDN 0x51 |
| + | |
| + | #define DHCP_END 0xFF |
| + | |
| + | |
| + | #define BOOTREQUEST 1 |
| + | #define BOOTREPLY 2 |
| + | |
| + | #define ETH_10MB 1 |
| + | #define ETH_10MB_LEN 6 |
| + | |
| + | #define DHCPDISCOVER 1 |
| + | #define DHCPOFFER 2 |
| + | #define DHCPREQUEST 3 |
| + | #define DHCPDECLINE 4 |
| + | #define DHCPACK 5 |
| + | #define DHCPNAK 6 |
| + | #define DHCPRELEASE 7 |
| + | #define DHCPINFORM 8 |
| + | |
| + | #define BROADCAST_FLAG 0x8000 |
| + | |
| + | #define OPTION_FIELD 0 |
| + | #define FILE_FIELD 1 |
| + | #define SNAME_FIELD 2 |
| + | |
| + | /* miscellaneous defines */ |
| + | #define MAC_BCAST_ADDR (uint8_t *) "\xff\xff\xff\xff\xff\xff" |
| + | #define OPT_CODE 0 |
| + | #define OPT_LEN 1 |
| + | #define OPT_DATA 2 |
| + | |
| + | struct option_set { |
| + | uint8_t *data; |
| + | struct option_set *next; |
| + | }; |
| + | |
| + | struct static_lease { |
| + | uint8_t *mac; |
| + | uint32_t *ip; |
| + | struct static_lease *next; |
| + | }; |
| + | |
| + | struct server_config_t { |
| + | uint32_t server; /* Our IP, in network order */ |
| + | uint32_t start; /* Start address of leases, network order */ |
| + | uint32_t end; /* End of leases, network order */ |
| + | struct option_set *options; /* List of DHCP options loaded from the config file */ |
| + | char *interface; /* The name of the interface to use */ |
| + | int ifindex; /* Index number of the interface to use */ |
| + | uint8_t arp[6]; /* Our arp address */ |
| + | unsigned long lease; /* lease time in seconds (host order) */ |
| + | unsigned long max_leases; /* maximum number of leases (including reserved address) */ |
| + | char remaining; /* should the lease file be interpreted as lease time remaining, or |
| + | * as the time the lease expires */ |
| + | unsigned long auto_time; /* how long should udhcpd wait before writing a config file. |
| + | * if this is zero, it will only write one on SIGUSR1 */ |
| + | unsigned long decline_time; /* how long an address is reserved if a client returns a |
| + | * decline message */ |
| + | unsigned long conflict_time; /* how long an arp conflict offender is leased for */ |
| + | unsigned long offer_time; /* how long an offered address is reserved */ |
| + | unsigned long min_lease; /* minimum lease a client can request*/ |
| + | char *lease_file; |
| + | char *pidfile; |
| + | char *notify_file; /* What to run whenever leases are written */ |
| + | uint32_t siaddr; /* next server bootp option */ |
| + | char *sname; /* bootp server name */ |
| + | char *boot_file; /* bootp boot file option */ |
| + | struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */ |
| + | }; |
| + | |
| + | extern struct server_config_t server_config; |
| + | extern struct dhcpOfferedAddr *leases; |
| + | |
| + | |
| + | #endif |
| @@ -0,0 +1,30 @@ | |
| + | .TH DUMPLEASES 1 2001-09-27 GNU/Linux "GNU/Linux Administrator's Manual" |
| + | .SH NAME |
| + | dumpleases \- display leases granted by udhcp server |
| + | .SH SYNOPSIS |
| + | .B dumpleases |
| + | .RI [ OPTION ]... |
| + | .SH DESCRIPTION |
| + | Display the DHCP leases granted by |
| + | .BR udhcpd (8). |
| + | .SH OPTIONS |
| + | .TP |
| + | .BR \-a ,\ \-\-absolute |
| + | Interpret lease times as expiration time. |
| + | .TP |
| + | .BI \-f\ FILE,\ \-\-file= FILE |
| + | Read lease information from |
| + | .IR FILE . |
| + | .TP |
| + | .BR \-h ,\ \-\-help |
| + | Display help. |
| + | .TP |
| + | .BR \-r ,\ \-\-remaining |
| + | Interpret lease times as remaining time. |
| + | .SH FILES |
| + | .TP |
| + | .I /var/lib/misc/udhcpd.leases |
| + | Lease information file. |
| + | .SH SEE ALSO |
| + | .BR udhcpd (8), |
| + | .BR udhcpd.conf (5). |
| @@ -0,0 +1,114 @@ | |
| + | /* vi: set sw=4 ts=4: */ |
| + | /* |
| + | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
| + | */ |
| + | #include <fcntl.h> |
| + | #include <string.h> |
| + | #include <stdlib.h> |
| + | #include <stdio.h> |
| + | #include <sys/wait.h> |
| + | #include <arpa/inet.h> |
| + | #include <netdb.h> |
| + | #include <netinet/in.h> |
| + | #include <stdio.h> |
| + | #include <sys/socket.h> |
| + | #include <unistd.h> |
| + | #include <getopt.h> |
| + | #include <time.h> |
| + | |
| + | #include "dhcpd.h" |
| + | #include "leases.h" |
| + | #include "libbb_udhcp.h" |
| + | |
| + | #define REMAINING 0 |
| + | #define ABSOLUTE 1 |
| + | |
| + | |
| + | #ifndef IN_BUSYBOX |
| + | static void ATTRIBUTE_NORETURN show_usage(void) |
| + | { |
| + | printf( |
| + | "Usage: dumpleases -f <file> -[r|a]\n\n" |
| + | " -f, --file=FILENAME Leases file to load\n" |
| + | " -r, --remaining Interepret lease times as time remaing\n" |
| + | " -a, --absolute Interepret lease times as expire time\n"); |
| + | exit(0); |
| + | } |
| + | #else |
| + | #define show_usage bb_show_usage |
| + | #endif |
| + | |
| + | |
| + | #ifdef IN_BUSYBOX |
| + | int dumpleases_main(int argc, char *argv[]) |
| + | #else |
| + | int main(int argc, char *argv[]) |
| + | #endif |
| + | { |
| + | FILE *fp; |
| + | int i, c, mode = REMAINING; |
| + | long expires; |
| + | const char *file = LEASES_FILE; |
| + | struct dhcpOfferedAddr lease; |
| + | struct in_addr addr; |
| + | |
| + | static const struct option options[] = { |
| + | {"absolute", 0, 0, 'a'}, |
| + | {"remaining", 0, 0, 'r'}, |
| + | {"file", 1, 0, 'f'}, |
| + | {0, 0, 0, 0} |
| + | }; |
| + | |
| + | while (1) { |
| + | int option_index = 0; |
| + | c = getopt_long(argc, argv, "arf:", options, &option_index); |
| + | if (c == -1) break; |
| + | |
| + | switch (c) { |
| + | case 'a': mode = ABSOLUTE; break; |
| + | case 'r': mode = REMAINING; break; |
| + | case 'f': |
| + | file = optarg; |
| + | break; |
| + | default: |
| + | show_usage(); |
| + | } |
| + | } |
| + | |
| + | fp = xfopen(file, "r"); |
| + | |
| + | printf("Mac Address IP-Address Expires %s\n", mode == REMAINING ? "in" : "at"); |
| + | /* "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */ |
| + | while (fread(&lease, sizeof(lease), 1, fp)) { |
| + | |
| + | for (i = 0; i < 6; i++) { |
| + | printf("%02x", lease.chaddr[i]); |
| + | if (i != 5) printf(":"); |
| + | } |
| + | addr.s_addr = lease.yiaddr; |
| + | printf(" %-15s", inet_ntoa(addr)); |
| + | expires = ntohl(lease.expires); |
| + | printf(" "); |
| + | if (mode == REMAINING) { |
| + | if (!expires) printf("expired\n"); |
| + | else { |
| + | if (expires > 60*60*24) { |
| + | printf("%ld days, ", expires / (60*60*24)); |
| + | expires %= 60*60*24; |
| + | } |
| + | if (expires > 60*60) { |
| + | printf("%ld hours, ", expires / (60*60)); |
| + | expires %= 60*60; |
| + | } |
| + | if (expires > 60) { |
| + | printf("%ld minutes, ", expires / 60); |
| + | expires %= 60; |
| + | } |
| + | printf("%ld seconds\n", expires); |
| + | } |
| + | } else printf("%s", ctime(&expires)); |
| + | } |
| + | fclose(fp); |
| + | |
| + | return 0; |
| + | } |
| @@ -0,0 +1,393 @@ | |
| + | /* |
| + | * files.c -- DHCP server file manipulation * |
| + | * Rewrite by Russ Dill <[email protected]> July 2001 |
| + | */ |
| + | |
| + | #include <sys/socket.h> |
| + | #include <arpa/inet.h> |
| + | #include <string.h> |
| + | #include <stdlib.h> |
| + | #include <time.h> |
| + | #include <ctype.h> |
| + | #include <netdb.h> |
| + | |
| + | #include <netinet/ether.h> |
| + | #include "static_leases.h" |
| + | |
| + | #include "dhcpd.h" |
| + | #include "options.h" |
| + | #include "files.h" |
| + | #include "common.h" |
| + | |
| + | /* |
| + | * Domain names may have 254 chars, and string options can be 254 |
| + | * chars long. However, 80 bytes will be enough for most, and won't |
| + | * hog up memory. If you have a special application, change it |
| + | */ |
| + | #define READ_CONFIG_BUF_SIZE 80 |
| + | |
| + | /* on these functions, make sure you datatype matches */ |
| + | static int read_ip(const char *line, void *arg) |
| + | { |
| + | struct in_addr *addr = arg; |
| + | struct hostent *host; |
| + | int retval = 1; |
| + | |
| + | if (!inet_aton(line, addr)) { |
| + | if ((host = gethostbyname(line))) |
| + | addr->s_addr = *((unsigned long *) host->h_addr_list[0]); |
| + | else retval = 0; |
| + | } |
| + | return retval; |
| + | } |
| + | |
| + | static int read_mac(const char *line, void *arg) |
| + | { |
| + | uint8_t *mac_bytes = arg; |
| + | struct ether_addr *temp_ether_addr; |
| + | int retval = 1; |
| + | |
| + | temp_ether_addr = ether_aton(line); |
| + | |
| + | if(temp_ether_addr == NULL) |
| + | retval = 0; |
| + | else |
| + | memcpy(mac_bytes, temp_ether_addr, 6); |
| + | |
| + | return retval; |
| + | } |
| + | |
| + | |
| + | static int read_str(const char *line, void *arg) |
| + | { |
| + | char **dest = arg; |
| + | |
| + | free(*dest); |
| + | *dest = strdup(line); |
| + | |
| + | return 1; |
| + | } |
| + | |
| + | |
| + | static int read_u32(const char *line, void *arg) |
| + | { |
| + | uint32_t *dest = arg; |
| + | char *endptr; |
| + | *dest = strtoul(line, &endptr, 0); |
| + | return endptr[0] == '\0'; |
| + | } |
| + | |
| + | |
| + | static int read_yn(const char *line, void *arg) |
| + | { |
| + | char *dest = arg; |
| + | int retval = 1; |
| + | |
| + | if (!strcasecmp("yes", line)) |
| + | *dest = 1; |
| + | else if (!strcasecmp("no", line)) |
| + | *dest = 0; |
| + | else retval = 0; |
| + | |
| + | return retval; |
| + | } |
| + | |
| + | |
| + | /* find option 'code' in opt_list */ |
| + | struct option_set *find_option(struct option_set *opt_list, char code) |
| + | { |
| + | while (opt_list && opt_list->data[OPT_CODE] < code) |
| + | opt_list = opt_list->next; |
| + | |
| + | if (opt_list && opt_list->data[OPT_CODE] == code) return opt_list; |
| + | else return NULL; |
| + | } |
| + | |
| + | |
| + | /* add an option to the opt_list */ |
| + | static void attach_option(struct option_set **opt_list, struct dhcp_option *option, char *buffer, int length) |
| + | { |
| + | struct option_set *existing, *new, **curr; |
| + | |
| + | /* add it to an existing option */ |
| + | if ((existing = find_option(*opt_list, option->code))) { |
| + | DEBUG(LOG_INFO, "Attaching option %s to existing member of list", option->name); |
| + | if (option->flags & OPTION_LIST) { |
| + | if (existing->data[OPT_LEN] + length <= 255) { |
| + | existing->data = realloc(existing->data, |
| + | existing->data[OPT_LEN] + length + 2); |
| + | memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length); |
| + | existing->data[OPT_LEN] += length; |
| + | } /* else, ignore the data, we could put this in a second option in the future */ |
| + | } /* else, ignore the new data */ |
| + | } else { |
| + | DEBUG(LOG_INFO, "Attaching option %s to list", option->name); |
| + | |
| + | /* make a new option */ |
| + | new = xmalloc(sizeof(struct option_set)); |
| + | new->data = xmalloc(length + 2); |
| + | new->data[OPT_CODE] = option->code; |
| + | new->data[OPT_LEN] = length; |
| + | memcpy(new->data + 2, buffer, length); |
| + | |
| + | curr = opt_list; |
| + | while (*curr && (*curr)->data[OPT_CODE] < option->code) |
| + | curr = &(*curr)->next; |
| + | |
| + | new->next = *curr; |
| + | *curr = new; |
| + | } |
| + | } |
| + | |
| + | |
| + | /* read a dhcp option and add it to opt_list */ |
| + | static int read_opt(const char *const_line, void *arg) |
| + | { |
| + | struct option_set **opt_list = arg; |
| + | char *opt, *val, *endptr; |
| + | struct dhcp_option *option; |
| + | int retval = 0, length; |
| + | char buffer[8]; |
| + | char *line; |
| + | uint16_t *result_u16 = (uint16_t *) buffer; |
| + | uint32_t *result_u32 = (uint32_t *) buffer; |
| + | |
| + | /* Cheat, the only const line we'll actually get is "" */ |
| + | line = (char *) const_line; |
| + | if (!(opt = strtok(line, " \t="))) return 0; |
| + | |
| + | for (option = dhcp_options; option->code; option++) |
| + | if (!strcasecmp(option->name, opt)) |
| + | break; |
| + | |
| + | if (!option->code) return 0; |
| + | |
| + | do { |
| + | if (!(val = strtok(NULL, ", \t"))) break; |
| + | length = option_lengths[option->flags & TYPE_MASK]; |
| + | retval = 0; |
| + | opt = buffer; /* new meaning for variable opt */ |
| + | switch (option->flags & TYPE_MASK) { |
| + | case OPTION_IP: |
| + | retval = read_ip(val, buffer); |
| + | break; |
| + | case OPTION_IP_PAIR: |
| + | retval = read_ip(val, buffer); |
| + | if (!(val = strtok(NULL, ", \t/-"))) retval = 0; |
| + | if (retval) retval = read_ip(val, buffer + 4); |
| + | break; |
| + | case OPTION_STRING: |
| + | length = strlen(val); |
| + | if (length > 0) { |
| + | if (length > 254) length = 254; |
| + | opt = val; |
| + | retval = 1; |
| + | } |
| + | break; |
| + | case OPTION_BOOLEAN: |
| + | retval = read_yn(val, buffer); |
| + | break; |
| + | case OPTION_U8: |
| + | buffer[0] = strtoul(val, &endptr, 0); |
| + | retval = (endptr[0] == '\0'); |
| + | break; |
| + | case OPTION_U16: |
| + | *result_u16 = htons(strtoul(val, &endptr, 0)); |
| + | retval = (endptr[0] == '\0'); |
| + | break; |
| + | case OPTION_S16: |
| + | *result_u16 = htons(strtol(val, &endptr, 0)); |
| + | retval = (endptr[0] == '\0'); |
| + | break; |
| + | case OPTION_U32: |
| + | *result_u32 = htonl(strtoul(val, &endptr, 0)); |
| + | retval = (endptr[0] == '\0'); |
| + | break; |
| + | case OPTION_S32: |
| + | *result_u32 = htonl(strtol(val, &endptr, 0)); |
| + | retval = (endptr[0] == '\0'); |
| + | break; |
| + | default: |
| + | break; |
| + | } |
| + | if (retval) |
| + | attach_option(opt_list, option, opt, length); |
| + | } while (retval && option->flags & OPTION_LIST); |
| + | return retval; |
| + | } |
| + | |
| + | static int read_staticlease(const char *const_line, void *arg) |
| + | { |
| + | |
| + | char *line; |
| + | char *mac_string; |
| + | char *ip_string; |
| + | uint8_t *mac_bytes; |
| + | uint32_t *ip; |
| + | |
| + | |
| + | /* Allocate memory for addresses */ |
| + | mac_bytes = xmalloc(sizeof(unsigned char) * 8); |
| + | ip = xmalloc(sizeof(uint32_t)); |
| + | |
| + | /* Read mac */ |
| + | line = (char *) const_line; |
| + | mac_string = strtok(line, " \t"); |
| + | read_mac(mac_string, mac_bytes); |
| + | |
| + | /* Read ip */ |
| + | ip_string = strtok(NULL, " \t"); |
| + | read_ip(ip_string, ip); |
| + | |
| + | addStaticLease(arg, mac_bytes, ip); |
| + | |
| + | #ifdef UDHCP_DEBUG |
| + | printStaticLeases(arg); |
| + | #endif |
| + | |
| + | return 1; |
| + | |
| + | } |
| + | |
| + | |
| + | static const struct config_keyword keywords[] = { |
| + | /* keyword handler variable address default */ |
| + | {"start", read_ip, &(server_config.start), "192.168.0.20"}, |
| + | {"end", read_ip, &(server_config.end), "192.168.0.254"}, |
| + | {"interface", read_str, &(server_config.interface), "eth0"}, |
| + | {"option", read_opt, &(server_config.options), ""}, |
| + | {"opt", read_opt, &(server_config.options), ""}, |
| + | {"max_leases", read_u32, &(server_config.max_leases), "254"}, |
| + | {"remaining", read_yn, &(server_config.remaining), "yes"}, |
| + | {"auto_time", read_u32, &(server_config.auto_time), "7200"}, |
| + | {"decline_time",read_u32, &(server_config.decline_time),"3600"}, |
| + | {"conflict_time",read_u32,&(server_config.conflict_time),"3600"}, |
| + | {"offer_time", read_u32, &(server_config.offer_time), "60"}, |
| + | {"min_lease", read_u32, &(server_config.min_lease), "60"}, |
| + | {"lease_file", read_str, &(server_config.lease_file), LEASES_FILE}, |
| + | {"pidfile", read_str, &(server_config.pidfile), "/var/run/udhcpd.pid"}, |
| + | {"notify_file", read_str, &(server_config.notify_file), ""}, |
| + | {"siaddr", read_ip, &(server_config.siaddr), "0.0.0.0"}, |
| + | {"sname", read_str, &(server_config.sname), ""}, |
| + | {"boot_file", read_str, &(server_config.boot_file), ""}, |
| + | {"static_lease",read_staticlease, &(server_config.static_leases), ""}, |
| + | /*ADDME: static lease */ |
| + | {"", NULL, NULL, ""} |
| + | }; |
| + | |
| + | |
| + | int read_config(const char *file) |
| + | { |
| + | FILE *in; |
| + | char buffer[READ_CONFIG_BUF_SIZE], *token, *line; |
| + | #ifdef UDHCP_DEBUG |
| + | char orig[READ_CONFIG_BUF_SIZE]; |
| + | #endif |
| + | int i, lm = 0; |
| + | |
| + | for (i = 0; keywords[i].keyword[0]; i++) |
| + | if (keywords[i].def[0]) |
| + | keywords[i].handler(keywords[i].def, keywords[i].var); |
| + | |
| + | if (!(in = fopen(file, "r"))) { |
| + | LOG(LOG_ERR, "unable to open config file: %s", file); |
| + | return 0; |
| + | } |
| + | |
| + | while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) { |
| + | lm++; |
| + | if (strchr(buffer, '\n')) *(strchr(buffer, '\n')) = '\0'; |
| + | #ifdef UDHCP_DEBUG |
| + | strcpy(orig, buffer); |
| + | #endif |
| + | if (strchr(buffer, '#')) *(strchr(buffer, '#')) = '\0'; |
| + | |
| + | if (!(token = strtok(buffer, " \t"))) continue; |
| + | if (!(line = strtok(NULL, ""))) continue; |
| + | |
| + | /* eat leading whitespace */ |
| + | line = line + strspn(line, " \t="); |
| + | /* eat trailing whitespace */ |
| + | for (i = strlen(line); i > 0 && isspace(line[i - 1]); i--); |
| + | line[i] = '\0'; |
| + | |
| + | for (i = 0; keywords[i].keyword[0]; i++) |
| + | if (!strcasecmp(token, keywords[i].keyword)) |
| + | if (!keywords[i].handler(line, keywords[i].var)) { |
| + | LOG(LOG_ERR, "Failure parsing line %d of %s", lm, file); |
| + | DEBUG(LOG_ERR, "unable to parse '%s'", orig); |
| + | /* reset back to the default value */ |
| + | keywords[i].handler(keywords[i].def, keywords[i].var); |
| + | } |
| + | } |
| + | fclose(in); |
| + | return 1; |
| + | } |
| + | |
| + | |
| + | void write_leases(void) |
| + | { |
| + | FILE *fp; |
| + | unsigned int i; |
| + | char buf[255]; |
| + | time_t curr = time(0); |
| + | unsigned long tmp_time; |
| + | |
| + | if (!(fp = fopen(server_config.lease_file, "w"))) { |
| + | LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file); |
| + | return; |
| + | } |
| + | |
| + | for (i = 0; i < server_config.max_leases; i++) { |
| + | if (leases[i].yiaddr != 0) { |
| + | |
| + | /* screw with the time in the struct, for easier writing */ |
| + | tmp_time = leases[i].expires; |
| + | |
| + | if (server_config.remaining) { |
| + | if (lease_expired(&(leases[i]))) |
| + | leases[i].expires = 0; |
| + | else leases[i].expires -= curr; |
| + | } /* else stick with the time we got */ |
| + | leases[i].expires = htonl(leases[i].expires); |
| + | fwrite(&leases[i], sizeof(struct dhcpOfferedAddr), 1, fp); |
| + | |
| + | /* Then restore it when done. */ |
| + | leases[i].expires = tmp_time; |
| + | } |
| + | } |
| + | fclose(fp); |
| + | |
| + | if (server_config.notify_file) { |
| + | sprintf(buf, "%s %s", server_config.notify_file, server_config.lease_file); |
| + | system(buf); |
| + | } |
| + | } |
| + | |
| + | |
| + | void read_leases(const char *file) |
| + | { |
| + | FILE *fp; |
| + | unsigned int i = 0; |
| + | struct dhcpOfferedAddr lease; |
| + | |
| + | if (!(fp = fopen(file, "r"))) { |
| + | LOG(LOG_ERR, "Unable to open %s for reading", file); |
| + | return; |
| + | } |
| + | |
| + | while (i < server_config.max_leases && (fread(&lease, sizeof lease, 1, fp) == 1)) { |
| + | /* ADDME: is it a static lease */ |
| + | if (lease.yiaddr >= server_config.start && lease.yiaddr <= server_config.end) { |
| + | lease.expires = ntohl(lease.expires); |
| + | if (!server_config.remaining) lease.expires -= time(0); |
| + | if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) { |
| + | LOG(LOG_WARNING, "Too many leases while loading %s\n", file); |
| + | break; |
| + | } |
| + | i++; |
| + | } |
| + | } |
| + | DEBUG(LOG_INFO, "Read %d leases", i); |
| + | fclose(fp); |
| + | } |
| @@ -0,0 +1,19 @@ | |
| + | /* files.h */ |
| + | #ifndef _FILES_H |
| + | #define _FILES_H |
| + | |
| + | struct config_keyword { |
| + | const char *keyword; |
| + | int (* const handler)(const char *line, void *var); |
| + | void *var; |
| + | const char *def; |
| + | }; |
| + | |
| + | |
| + | int read_config(const char *file); |
| + | void write_leases(void); |
| + | void read_leases(const char *file); |
| + | |
| + | struct option_set *find_option(struct option_set *opt_list, char code); |
| + | |
| + | #endif |
| @@ -0,0 +1,16 @@ | |
| + | #include <string.h> |
| + | |
| + | extern int udhcpd_main(int argc, char *argv[]); |
| + | extern int udhcpc_main(int argc, char *argv[]); |
| + | |
| + | int main(int argc, char *argv[]) |
| + | { |
| + | int ret = 0; |
| + | char *base = strrchr(argv[0], '/'); |
| + | |
| + | if (strstr(base ? (base + 1) : argv[0], "dhcpd")) |
| + | ret = udhcpd_main(argc, argv); |
| + | else ret = udhcpc_main(argc, argv); |
| + | |
| + | return ret; |
| + | } |
| @@ -0,0 +1,158 @@ | |
| + | /* |
| + | * leases.c -- tools to manage DHCP leases |
| + | * Russ Dill <[email protected]> July 2001 |
| + | */ |
| + | |
| + | #include <time.h> |
| + | #include <string.h> |
| + | #include <sys/socket.h> |
| + | #include <netinet/in.h> |
| + | #include <arpa/inet.h> |
| + | |
| + | #include "dhcpd.h" |
| + | #include "files.h" |
| + | #include "options.h" |
| + | #include "leases.h" |
| + | #include "arpping.h" |
| + | #include "common.h" |
| + | |
| + | #include "static_leases.h" |
| + | |
| + | |
| + | uint8_t blank_chaddr[] = {[0 ... 15] = 0}; |
| + | |
| + | /* clear every lease out that chaddr OR yiaddr matches and is nonzero */ |
| + | void clear_lease(uint8_t *chaddr, uint32_t yiaddr) |
| + | { |
| + | unsigned int i, j; |
| + | |
| + | for (j = 0; j < 16 && !chaddr[j]; j++); |
| + | |
| + | for (i = 0; i < server_config.max_leases; i++) |
| + | if ((j != 16 && !memcmp(leases[i].chaddr, chaddr, 16)) || |
| + | (yiaddr && leases[i].yiaddr == yiaddr)) { |
| + | memset(&(leases[i]), 0, sizeof(struct dhcpOfferedAddr)); |
| + | } |
| + | } |
| + | |
| + | |
| + | /* add a lease into the table, clearing out any old ones */ |
| + | struct dhcpOfferedAddr *add_lease(uint8_t *chaddr, uint32_t yiaddr, unsigned long lease) |
| + | { |
| + | struct dhcpOfferedAddr *oldest; |
| + | |
| + | /* clean out any old ones */ |
| + | clear_lease(chaddr, yiaddr); |
| + | |
| + | oldest = oldest_expired_lease(); |
| + | |
| + | if (oldest) { |
| + | memcpy(oldest->chaddr, chaddr, 16); |
| + | oldest->yiaddr = yiaddr; |
| + | oldest->expires = time(0) + lease; |
| + | } |
| + | |
| + | return oldest; |
| + | } |
| + | |
| + | |
| + | /* true if a lease has expired */ |
| + | int lease_expired(struct dhcpOfferedAddr *lease) |
| + | { |
| + | return (lease->expires < (unsigned long) time(0)); |
| + | } |
| + | |
| + | |
| + | /* Find the oldest expired lease, NULL if there are no expired leases */ |
| + | struct dhcpOfferedAddr *oldest_expired_lease(void) |
| + | { |
| + | struct dhcpOfferedAddr *oldest = NULL; |
| + | unsigned long oldest_lease = time(0); |
| + | unsigned int i; |
| + | |
| + | |
| + | for (i = 0; i < server_config.max_leases; i++) |
| + | if (oldest_lease > leases[i].expires) { |
| + | oldest_lease = leases[i].expires; |
| + | oldest = &(leases[i]); |
| + | } |
| + | return oldest; |
| + | |
| + | } |
| + | |
| + | |
| + | /* Find the first lease that matches chaddr, NULL if no match */ |
| + | struct dhcpOfferedAddr *find_lease_by_chaddr(uint8_t *chaddr) |
| + | { |
| + | unsigned int i; |
| + | |
| + | for (i = 0; i < server_config.max_leases; i++) |
| + | if (!memcmp(leases[i].chaddr, chaddr, 16)) return &(leases[i]); |
| + | |
| + | return NULL; |
| + | } |
| + | |
| + | |
| + | /* Find the first lease that matches yiaddr, NULL is no match */ |
| + | struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr) |
| + | { |
| + | unsigned int i; |
| + | |
| + | for (i = 0; i < server_config.max_leases; i++) |
| + | if (leases[i].yiaddr == yiaddr) return &(leases[i]); |
| + | |
| + | return NULL; |
| + | } |
| + | |
| + | |
| + | /* check is an IP is taken, if it is, add it to the lease table */ |
| + | static int check_ip(uint32_t addr) |
| + | { |
| + | struct in_addr temp; |
| + | |
| + | if (arpping(addr, server_config.server, server_config.arp, server_config.interface) == 0) { |
| + | temp.s_addr = addr; |
| + | LOG(LOG_INFO, "%s belongs to someone, reserving it for %ld seconds", |
| + | inet_ntoa(temp), server_config.conflict_time); |
| + | add_lease(blank_chaddr, addr, server_config.conflict_time); |
| + | return 1; |
| + | } else return 0; |
| + | } |
| + | |
| + | |
| + | /* find an assignable address, it check_expired is true, we check all the expired leases as well. |
| + | * Maybe this should try expired leases by age... */ |
| + | uint32_t find_address(int check_expired) |
| + | { |
| + | uint32_t addr, ret; |
| + | struct dhcpOfferedAddr *lease = NULL; |
| + | |
| + | addr = ntohl(server_config.start); /* addr is in host order here */ |
| + | for (;addr <= ntohl(server_config.end); addr++) { |
| + | |
| + | /* ie, 192.168.55.0 */ |
| + | if (!(addr & 0xFF)) continue; |
| + | |
| + | /* ie, 192.168.55.255 */ |
| + | if ((addr & 0xFF) == 0xFF) continue; |
| + | |
| + | /* Only do if it isn't an assigned as a static lease */ |
| + | if(!reservedIp(server_config.static_leases, htonl(addr))) |
| + | { |
| + | |
| + | /* lease is not taken */ |
| + | ret = htonl(addr); |
| + | if ((!(lease = find_lease_by_yiaddr(ret)) || |
| + | |
| + | /* or it expired and we are checking for expired leases */ |
| + | (check_expired && lease_expired(lease))) && |
| + | |
| + | /* and it isn't on the network */ |
| + | !check_ip(ret)) { |
| + | return ret; |
| + | break; |
| + | } |
| + | } |
| + | } |
| + | return 0; |
| + | } |
| @@ -0,0 +1,23 @@ | |
| + | /* leases.h */ |
| + | #ifndef _LEASES_H |
| + | #define _LEASES_H |
| + | |
| + | |
| + | struct dhcpOfferedAddr { |
| + | uint8_t chaddr[16]; |
| + | uint32_t yiaddr; /* network order */ |
| + | uint32_t expires; /* host order */ |
| + | }; |
| + | |
| + | extern uint8_t blank_chaddr[]; |
| + | |
| + | void clear_lease(uint8_t *chaddr, uint32_t yiaddr); |
| + | struct dhcpOfferedAddr *add_lease(uint8_t *chaddr, uint32_t yiaddr, unsigned long lease); |
| + | int lease_expired(struct dhcpOfferedAddr *lease); |
| + | struct dhcpOfferedAddr *oldest_expired_lease(void); |
| + | struct dhcpOfferedAddr *find_lease_by_chaddr(uint8_t *chaddr); |
| + | struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr); |
| + | uint32_t find_address(int check_expired); |
| + | |
| + | |
| + | #endif |
| @@ -0,0 +1,92 @@ | |
| + | /* libbb_udhcp.h - busybox compatibility wrapper */ |
| + | |
| + | /* bit of a hack, do this no matter what the order of the includes. |
| + | * (for busybox) */ |
| + | |
| + | #ifndef _LIBBB_UDHCP_H |
| + | #define _LIBBB_UDHCP_H |
| + | |
| + | #ifdef CONFIG_INSTALL_NO_USR |
| + | # define DEFAULT_SCRIPT "/share/udhcpc/default.script" |
| + | #else |
| + | # define DEFAULT_SCRIPT "/usr/share/udhcpc/default.script" |
| + | #endif |
| + | |
| + | #ifdef IN_BUSYBOX |
| + | #include "busybox.h" |
| + | |
| + | #ifdef CONFIG_FEATURE_UDHCP_SYSLOG |
| + | #define UDHCP_SYSLOG |
| + | #endif |
| + | |
| + | #ifdef CONFIG_FEATURE_UDHCP_DEBUG |
| + | #define UDHCP_DEBUG |
| + | #endif |
| + | |
| + | #define COMBINED_BINARY |
| + | #include "version.h" |
| + | |
| + | #define xfopen bb_xfopen |
| + | |
| + | /* make safe the exported namespace */ |
| + | /* from common.h */ |
| + | #define background udhcp_background |
| + | #define start_log_and_pid udhcp_start_log_and_pid |
| + | /* from script.h */ |
| + | #define run_script udhcp_run_script |
| + | /* from packet.h */ |
| + | #define init_header udhcp_init_header |
| + | #define get_packet udhcp_get_packet |
| + | #define checksum udhcp_checksum |
| + | #define raw_packet udhcp_raw_packet |
| + | #define kernel_packet udhcp_kernel_packet |
| + | /* from pidfile.h */ |
| + | #define pidfile_acquire udhcp_pidfile_acquire |
| + | #define pidfile_write_release udhcp_pidfile_write_release |
| + | /* from options.h */ |
| + | #define get_option udhcp_get_option |
| + | #define end_option udhcp_end_option |
| + | #define add_option_string udhcp_add_option_string |
| + | #define add_simple_option udhcp_add_simple_option |
| + | #define option_lengths udhcp_option_lengths |
| + | /* from socket.h */ |
| + | #define listen_socket udhcp_listen_socket |
| + | #define read_interface udhcp_read_interface |
| + | /* from dhcpc.h */ |
| + | #define client_config udhcp_client_config |
| + | /* from dhcpd.h */ |
| + | #define server_config udhcp_server_config |
| + | |
| + | #else /* ! IN_BUSYBOX */ |
| + | |
| + | #include <stdlib.h> |
| + | #include <stdio.h> |
| + | #include <sys/sysinfo.h> |
| + | |
| + | #ifndef ATTRIBUTE_NORETURN |
| + | #define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) |
| + | #endif /* ATTRIBUTE_NORETURN */ |
| + | |
| + | #ifndef ATTRIBUTE_PACKED |
| + | #define ATTRIBUTE_PACKED __attribute__ ((__packed__)) |
| + | #endif /* ATTRIBUTE_PACKED */ |
| + | |
| + | #define TRUE 1 |
| + | #define FALSE 0 |
| + | |
| + | #define xmalloc malloc |
| + | #define xcalloc calloc |
| + | |
| + | static inline FILE *xfopen(const char *file, const char *mode) |
| + | { |
| + | FILE *fp; |
| + | if (!(fp = fopen(file, mode))) { |
| + | perror("could not open input file"); |
| + | exit(0); |
| + | } |
| + | return fp; |
| + | } |
| + | |
| + | #endif /* IN_BUSYBOX */ |
| + | |
| + | #endif /* _LIBBB_UDHCP_H */ |
| @@ -0,0 +1,172 @@ | |
| + | /* |
| + | * options.c -- DHCP server option packet tools |
| + | * Rewrite by Russ Dill <[email protected]> July 2001 |
| + | */ |
| + | |
| + | #include <stdlib.h> |
| + | #include <string.h> |
| + | |
| + | #include "common.h" |
| + | #include "dhcpd.h" |
| + | #include "options.h" |
| + | #include "files.h" |
| + | |
| + | |
| + | /* supported options are easily added here */ |
| + | struct dhcp_option dhcp_options[] = { |
| + | /* name[10] flags code */ |
| + | {"subnet", OPTION_IP | OPTION_REQ, 0x01}, |
| + | {"timezone", OPTION_S32, 0x02}, |
| + | {"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03}, |
| + | {"timesvr", OPTION_IP | OPTION_LIST, 0x04}, |
| + | {"namesvr", OPTION_IP | OPTION_LIST, 0x05}, |
| + | {"dns", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06}, |
| + | {"logsvr", OPTION_IP | OPTION_LIST, 0x07}, |
| + | {"cookiesvr", OPTION_IP | OPTION_LIST, 0x08}, |
| + | {"lprsvr", OPTION_IP | OPTION_LIST, 0x09}, |
| + | {"hostname", OPTION_STRING | OPTION_REQ, 0x0c}, |
| + | {"bootsize", OPTION_U16, 0x0d}, |
| + | {"domain", OPTION_STRING | OPTION_REQ, 0x0f}, |
| + | {"swapsvr", OPTION_IP, 0x10}, |
| + | {"rootpath", OPTION_STRING, 0x11}, |
| + | {"ipttl", OPTION_U8, 0x17}, |
| + | {"mtu", OPTION_U16, 0x1a}, |
| + | {"broadcast", OPTION_IP | OPTION_REQ, 0x1c}, |
| + | {"nisdomain", OPTION_STRING | OPTION_REQ, 0x28}, |
| + | {"nissrv", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x29}, |
| + | {"ntpsrv", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a}, |
| + | {"wins", OPTION_IP | OPTION_LIST, 0x2c}, |
| + | {"requestip", OPTION_IP, 0x32}, |
| + | {"lease", OPTION_U32, 0x33}, |
| + | {"dhcptype", OPTION_U8, 0x35}, |
| + | {"serverid", OPTION_IP, 0x36}, |
| + | {"message", OPTION_STRING, 0x38}, |
| + | {"tftp", OPTION_STRING, 0x42}, |
| + | {"bootfile", OPTION_STRING, 0x43}, |
| + | {"", 0x00, 0x00} |
| + | }; |
| + | |
| + | /* Lengths of the different option types */ |
| + | int option_lengths[] = { |
| + | [OPTION_IP] = 4, |
| + | [OPTION_IP_PAIR] = 8, |
| + | [OPTION_BOOLEAN] = 1, |
| + | [OPTION_STRING] = 1, |
| + | [OPTION_U8] = 1, |
| + | [OPTION_U16] = 2, |
| + | [OPTION_S16] = 2, |
| + | [OPTION_U32] = 4, |
| + | [OPTION_S32] = 4 |
| + | }; |
| + | |
| + | |
| + | /* get an option with bounds checking (warning, not aligned). */ |
| + | uint8_t *get_option(struct dhcpMessage *packet, int code) |
| + | { |
| + | int i, length; |
| + | uint8_t *optionptr; |
| + | int over = 0, done = 0, curr = OPTION_FIELD; |
| + | |
| + | optionptr = packet->options; |
| + | i = 0; |
| + | length = 308; |
| + | while (!done) { |
| + | if (i >= length) { |
| + | LOG(LOG_WARNING, "bogus packet, option fields too long."); |
| + | return NULL; |
| + | } |
| + | if (optionptr[i + OPT_CODE] == code) { |
| + | if (i + 1 + optionptr[i + OPT_LEN] >= length) { |
| + | LOG(LOG_WARNING, "bogus packet, option fields too long."); |
| + | return NULL; |
| + | } |
| + | return optionptr + i + 2; |
| + | } |
| + | switch (optionptr[i + OPT_CODE]) { |
| + | case DHCP_PADDING: |
| + | i++; |
| + | break; |
| + | case DHCP_OPTION_OVER: |
| + | if (i + 1 + optionptr[i + OPT_LEN] >= length) { |
| + | LOG(LOG_WARNING, "bogus packet, option fields too long."); |
| + | return NULL; |
| + | } |
| + | over = optionptr[i + 3]; |
| + | i += optionptr[OPT_LEN] + 2; |
| + | break; |
| + | case DHCP_END: |
| + | if (curr == OPTION_FIELD && over & FILE_FIELD) { |
| + | optionptr = packet->file; |
| + | i = 0; |
| + | length = 128; |
| + | curr = FILE_FIELD; |
| + | } else if (curr == FILE_FIELD && over & SNAME_FIELD) { |
| + | optionptr = packet->sname; |
| + | i = 0; |
| + | length = 64; |
| + | curr = SNAME_FIELD; |
| + | } else done = 1; |
| + | break; |
| + | default: |
| + | i += optionptr[OPT_LEN + i] + 2; |
| + | } |
| + | } |
| + | return NULL; |
| + | } |
| + | |
| + | |
| + | /* return the position of the 'end' option (no bounds checking) */ |
| + | int end_option(uint8_t *optionptr) |
| + | { |
| + | int i = 0; |
| + | |
| + | while (optionptr[i] != DHCP_END) { |
| + | if (optionptr[i] == DHCP_PADDING) i++; |
| + | else i += optionptr[i + OPT_LEN] + 2; |
| + | } |
| + | return i; |
| + | } |
| + | |
| + | |
| + | /* add an option string to the options (an option string contains an option code, |
| + | * length, then data) */ |
| + | int add_option_string(uint8_t *optionptr, uint8_t *string) |
| + | { |
| + | int end = end_option(optionptr); |
| + | |
| + | /* end position + string length + option code/length + end option */ |
| + | if (end + string[OPT_LEN] + 2 + 1 >= 308) { |
| + | LOG(LOG_ERR, "Option 0x%02x did not fit into the packet!", string[OPT_CODE]); |
| + | return 0; |
| + | } |
| + | DEBUG(LOG_INFO, "adding option 0x%02x", string[OPT_CODE]); |
| + | memcpy(optionptr + end, string, string[OPT_LEN] + 2); |
| + | optionptr[end + string[OPT_LEN] + 2] = DHCP_END; |
| + | return string[OPT_LEN] + 2; |
| + | } |
| + | |
| + | |
| + | /* add a one to four byte option to a packet */ |
| + | int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data) |
| + | { |
| + | struct dhcp_option *dh; |
| + | |
| + | for (dh=dhcp_options; dh->code; dh++) { |
| + | if (dh->code == code) { |
| + | uint8_t option[6], len; |
| + | |
| + | option[OPT_CODE] = code; |
| + | len = option_lengths[dh->flags & TYPE_MASK]; |
| + | option[OPT_LEN] = len; |
| + | if (__BYTE_ORDER == __BIG_ENDIAN) |
| + | data <<= 8 * (4 - len); |
| + | /* This memcpy is for broken processors which can't |
| + | * handle a simple unaligned 32-bit assignment */ |
| + | memcpy(&option[OPT_DATA], &data, 4); |
| + | return add_option_string(optionptr, option); |
| + | } |
| + | } |
| + | |
| + | DEBUG(LOG_ERR, "Could not add option 0x%02x", code); |
| + | return 0; |
| + | } |
| @@ -0,0 +1,38 @@ | |
| + | /* options.h */ |
| + | #ifndef _OPTIONS_H |
| + | #define _OPTIONS_H |
| + | |
| + | #include "packet.h" |
| + | |
| + | #define TYPE_MASK 0x0F |
| + | |
| + | enum { |
| + | OPTION_IP=1, |
| + | OPTION_IP_PAIR, |
| + | OPTION_STRING, |
| + | OPTION_BOOLEAN, |
| + | OPTION_U8, |
| + | OPTION_U16, |
| + | OPTION_S16, |
| + | OPTION_U32, |
| + | OPTION_S32 |
| + | }; |
| + | |
| + | #define OPTION_REQ 0x10 /* have the client request this option */ |
| + | #define OPTION_LIST 0x20 /* There can be a list of 1 or more of these */ |
| + | |
| + | struct dhcp_option { |
| + | char name[10]; |
| + | char flags; |
| + | uint8_t code; |
| + | }; |
| + | |
| + | extern struct dhcp_option dhcp_options[]; |
| + | extern int option_lengths[]; |
| + | |
| + | uint8_t *get_option(struct dhcpMessage *packet, int code); |
| + | int end_option(uint8_t *optionptr); |
| + | int add_option_string(uint8_t *optionptr, uint8_t *string); |
| + | int add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data); |
| + | |
| + | #endif |
| @@ -0,0 +1,207 @@ | |
| + | #include <unistd.h> |
| + | #include <string.h> |
| + | #include <netinet/in.h> |
| + | #include <sys/types.h> |
| + | #include <sys/socket.h> |
| + | #include <features.h> |
| + | #if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION |
| + | #include <netpacket/packet.h> |
| + | #include <net/ethernet.h> |
| + | #else |
| + | #include <asm/types.h> |
| + | #include <linux/if_packet.h> |
| + | #include <linux/if_ether.h> |
| + | #endif |
| + | #include <errno.h> |
| + | |
| + | #include "common.h" |
| + | #include "packet.h" |
| + | #include "dhcpd.h" |
| + | #include "options.h" |
| + | |
| + | |
| + | void init_header(struct dhcpMessage *packet, char type) |
| + | { |
| + | memset(packet, 0, sizeof(struct dhcpMessage)); |
| + | switch (type) { |
| + | case DHCPDISCOVER: |
| + | case DHCPREQUEST: |
| + | case DHCPRELEASE: |
| + | case DHCPINFORM: |
| + | packet->op = BOOTREQUEST; |
| + | break; |
| + | case DHCPOFFER: |
| + | case DHCPACK: |
| + | case DHCPNAK: |
| + | packet->op = BOOTREPLY; |
| + | } |
| + | packet->htype = ETH_10MB; |
| + | packet->hlen = ETH_10MB_LEN; |
| + | packet->cookie = htonl(DHCP_MAGIC); |
| + | packet->options[0] = DHCP_END; |
| + | add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); |
| + | } |
| + | |
| + | |
| + | /* read a packet from socket fd, return -1 on read error, -2 on packet error */ |
| + | int get_packet(struct dhcpMessage *packet, int fd) |
| + | { |
| + | static const char broken_vendors[][8] = { |
| + | "MSFT 98", |
| + | "" |
| + | }; |
| + | int bytes; |
| + | int i; |
| + | char unsigned *vendor; |
| + | |
| + | memset(packet, 0, sizeof(struct dhcpMessage)); |
| + | bytes = read(fd, packet, sizeof(struct dhcpMessage)); |
| + | if (bytes < 0) { |
| + | DEBUG(LOG_INFO, "couldn't read on listening socket, ignoring"); |
| + | return -1; |
| + | } |
| + | |
| + | if (ntohl(packet->cookie) != DHCP_MAGIC) { |
| + | LOG(LOG_ERR, "received bogus message, ignoring"); |
| + | return -2; |
| + | } |
| + | DEBUG(LOG_INFO, "Received a packet"); |
| + | |
| + | if (packet->op == BOOTREQUEST && (vendor = get_option(packet, DHCP_VENDOR))) { |
| + | for (i = 0; broken_vendors[i][0]; i++) { |
| + | if (vendor[OPT_LEN - 2] == (uint8_t) strlen(broken_vendors[i]) && |
| + | !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2])) { |
| + | DEBUG(LOG_INFO, "broken client (%s), forcing broadcast", |
| + | broken_vendors[i]); |
| + | packet->flags |= htons(BROADCAST_FLAG); |
| + | } |
| + | } |
| + | } |
| + | |
| + | return bytes; |
| + | } |
| + | |
| + | |
| + | uint16_t checksum(void *addr, int count) |
| + | { |
| + | /* Compute Internet Checksum for "count" bytes |
| + | * beginning at location "addr". |
| + | */ |
| + | register int32_t sum = 0; |
| + | uint16_t *source = (uint16_t *) addr; |
| + | |
| + | while (count > 1) { |
| + | /* This is the inner loop */ |
| + | sum += *source++; |
| + | count -= 2; |
| + | } |
| + | |
| + | /* Add left-over byte, if any */ |
| + | if (count > 0) { |
| + | /* Make sure that the left-over byte is added correctly both |
| + | * with little and big endian hosts */ |
| + | uint16_t tmp = 0; |
| + | *(uint8_t *) (&tmp) = * (uint8_t *) source; |
| + | sum += tmp; |
| + | } |
| + | /* Fold 32-bit sum to 16 bits */ |
| + | while (sum >> 16) |
| + | sum = (sum & 0xffff) + (sum >> 16); |
| + | |
| + | return ~sum; |
| + | } |
| + | |
| + | |
| + | /* Construct a ip/udp header for a packet, and specify the source and dest hardware address */ |
| + | int raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port, |
| + | uint32_t dest_ip, int dest_port, uint8_t *dest_arp, int ifindex) |
| + | { |
| + | int fd; |
| + | int result; |
| + | struct sockaddr_ll dest; |
| + | struct udp_dhcp_packet packet; |
| + | |
| + | if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { |
| + | DEBUG(LOG_ERR, "socket call failed: %m"); |
| + | return -1; |
| + | } |
| + | |
| + | memset(&dest, 0, sizeof(dest)); |
| + | memset(&packet, 0, sizeof(packet)); |
| + | |
| + | dest.sll_family = AF_PACKET; |
| + | dest.sll_protocol = htons(ETH_P_IP); |
| + | dest.sll_ifindex = ifindex; |
| + | dest.sll_halen = 6; |
| + | memcpy(dest.sll_addr, dest_arp, 6); |
| + | if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) { |
| + | DEBUG(LOG_ERR, "bind call failed: %m"); |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | |
| + | packet.ip.protocol = IPPROTO_UDP; |
| + | packet.ip.saddr = source_ip; |
| + | packet.ip.daddr = dest_ip; |
| + | packet.udp.source = htons(source_port); |
| + | packet.udp.dest = htons(dest_port); |
| + | packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); /* cheat on the psuedo-header */ |
| + | packet.ip.tot_len = packet.udp.len; |
| + | memcpy(&(packet.data), payload, sizeof(struct dhcpMessage)); |
| + | packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet)); |
| + | |
| + | packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet)); |
| + | packet.ip.ihl = sizeof(packet.ip) >> 2; |
| + | packet.ip.version = IPVERSION; |
| + | packet.ip.ttl = IPDEFTTL; |
| + | packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip)); |
| + | |
| + | result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, (struct sockaddr *) &dest, sizeof(dest)); |
| + | if (result <= 0) { |
| + | DEBUG(LOG_ERR, "write on socket failed: %m"); |
| + | } |
| + | close(fd); |
| + | return result; |
| + | } |
| + | |
| + | |
| + | /* Let the kernel do all the work for packet generation */ |
| + | int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port, |
| + | uint32_t dest_ip, int dest_port) |
| + | { |
| + | int n = 1; |
| + | int fd, result; |
| + | struct sockaddr_in client; |
| + | |
| + | if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) |
| + | return -1; |
| + | |
| + | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) { |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | |
| + | memset(&client, 0, sizeof(client)); |
| + | client.sin_family = AF_INET; |
| + | client.sin_port = htons(source_port); |
| + | client.sin_addr.s_addr = source_ip; |
| + | |
| + | if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) { |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | |
| + | memset(&client, 0, sizeof(client)); |
| + | client.sin_family = AF_INET; |
| + | client.sin_port = htons(dest_port); |
| + | client.sin_addr.s_addr = dest_ip; |
| + | |
| + | if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) { |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | |
| + | result = write(fd, payload, sizeof(struct dhcpMessage)); |
| + | close(fd); |
| + | return result; |
| + | } |
| @@ -0,0 +1,41 @@ | |
| + | #ifndef _PACKET_H |
| + | #define _PACKET_H |
| + | |
| + | #include <netinet/udp.h> |
| + | #include <netinet/ip.h> |
| + | |
| + | struct dhcpMessage { |
| + | uint8_t op; |
| + | uint8_t htype; |
| + | uint8_t hlen; |
| + | uint8_t hops; |
| + | uint32_t xid; |
| + | uint16_t secs; |
| + | uint16_t flags; |
| + | uint32_t ciaddr; |
| + | uint32_t yiaddr; |
| + | uint32_t siaddr; |
| + | uint32_t giaddr; |
| + | uint8_t chaddr[16]; |
| + | uint8_t sname[64]; |
| + | uint8_t file[128]; |
| + | uint32_t cookie; |
| + | uint8_t options[308]; /* 312 - cookie */ |
| + | }; |
| + | |
| + | struct udp_dhcp_packet { |
| + | struct iphdr ip; |
| + | struct udphdr udp; |
| + | struct dhcpMessage data; |
| + | }; |
| + | |
| + | void init_header(struct dhcpMessage *packet, char type); |
| + | int get_packet(struct dhcpMessage *packet, int fd); |
| + | uint16_t checksum(void *addr, int count); |
| + | int raw_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port, |
| + | uint32_t dest_ip, int dest_port, uint8_t *dest_arp, int ifindex); |
| + | int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, int source_port, |
| + | uint32_t dest_ip, int dest_port); |
| + | |
| + | |
| + | #endif |
| @@ -0,0 +1,75 @@ | |
| + | /* pidfile.c |
| + | * |
| + | * Functions to assist in the writing and removing of pidfiles. |
| + | * |
| + | * Russ Dill <[email protected]> September 2001 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | #include <sys/types.h> |
| + | #include <sys/stat.h> |
| + | #include <fcntl.h> |
| + | #include <unistd.h> |
| + | #include <stdio.h> |
| + | #include <stdlib.h> |
| + | |
| + | #include "common.h" |
| + | #include "pidfile.h" |
| + | |
| + | static char *saved_pidfile; |
| + | |
| + | static void pidfile_delete(void) |
| + | { |
| + | if (saved_pidfile) unlink(saved_pidfile); |
| + | } |
| + | |
| + | |
| + | int pidfile_acquire(const char *pidfile) |
| + | { |
| + | int pid_fd; |
| + | if (!pidfile) return -1; |
| + | |
| + | pid_fd = open(pidfile, O_CREAT | O_WRONLY, 0644); |
| + | if (pid_fd < 0) { |
| + | LOG(LOG_ERR, "Unable to open pidfile %s: %m\n", pidfile); |
| + | } else { |
| + | lockf(pid_fd, F_LOCK, 0); |
| + | if (!saved_pidfile) |
| + | atexit(pidfile_delete); |
| + | saved_pidfile = (char *) pidfile; |
| + | } |
| + | |
| + | return pid_fd; |
| + | } |
| + | |
| + | |
| + | void pidfile_write_release(int pid_fd) |
| + | { |
| + | FILE *out; |
| + | |
| + | if (pid_fd < 0) return; |
| + | |
| + | if ((out = fdopen(pid_fd, "w")) != NULL) { |
| + | fprintf(out, "%d\n", getpid()); |
| + | fclose(out); |
| + | } |
| + | lockf(pid_fd, F_UNLCK, 0); |
| + | close(pid_fd); |
| + | } |
| + | |
| + | |
| + | |
| + | |
| @@ -0,0 +1,25 @@ | |
| + | /* pidfile.h |
| + | * |
| + | * Functions to assist in the writing and removing of pidfiles. |
| + | * |
| + | * Russ Dill <[email protected]> September 2001 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | |
| + | int pidfile_acquire(const char *pidfile); |
| + | void pidfile_write_release(int pid_fd); |
| + | |
| @@ -0,0 +1,11 @@ | |
| + | The files in this dir are: |
| + | |
| + | udhcpd.conf: A sample udhpcd configuration file. |
| + | |
| + | sample.script |
| + | sample.nak |
| + | sample.deconfig |
| + | sample.bound |
| + | sample.renew : sample scripts for the udhcpc client. |
| + | |
| + | simple.script : a simple sample script for the client. |
| @@ -0,0 +1,30 @@ | |
| + | #!/bin/sh |
| + | # Sample udhcpc renew script |
| + | |
| + | RESOLV_CONF="/etc/udhcpc/resolv.conf" |
| + | |
| + | [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" |
| + | [ -n "$subnet" ] && NETMASK="netmask $subnet" |
| + | |
| + | /sbin/ifconfig $interface $ip $BROADCAST $NETMASK |
| + | |
| + | if [ -n "$router" ] |
| + | then |
| + | echo "deleting routers" |
| + | while /sbin/route del default gw 0.0.0.0 dev $interface |
| + | do : |
| + | done |
| + | |
| + | for i in $router |
| + | do |
| + | /sbin/route add default gw $i dev $interface |
| + | done |
| + | fi |
| + | |
| + | echo -n > $RESOLV_CONF |
| + | [ -n "$domain" ] && echo domain $domain >> $RESOLV_CONF |
| + | for i in $dns |
| + | do |
| + | echo adding dns $i |
| + | echo nameserver $i >> $RESOLV_CONF |
| + | done |
| @@ -0,0 +1,4 @@ | |
| + | #!/bin/sh |
| + | # Sample udhcpc deconfig script |
| + | |
| + | /sbin/ifconfig $interface 0.0.0.0 |
| @@ -0,0 +1,4 @@ | |
| + | #!/bin/sh |
| + | # Sample udhcpc nak script |
| + | |
| + | echo Received a NAK: $message |
| @@ -0,0 +1,30 @@ | |
| + | #!/bin/sh |
| + | # Sample udhcpc bound script |
| + | |
| + | RESOLV_CONF="/etc/udhcpc/resolv.conf" |
| + | |
| + | [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" |
| + | [ -n "$subnet" ] && NETMASK="netmask $subnet" |
| + | |
| + | /sbin/ifconfig $interface $ip $BROADCAST $NETMASK |
| + | |
| + | if [ -n "$router" ] |
| + | then |
| + | echo "deleting routers" |
| + | while /sbin/route del default gw 0.0.0.0 dev $interface |
| + | do : |
| + | done |
| + | |
| + | for i in $router |
| + | do |
| + | /sbin/route add default gw $i dev $interface |
| + | done |
| + | fi |
| + | |
| + | echo -n > $RESOLV_CONF |
| + | [ -n "$domain" ] && echo domain $domain >> $RESOLV_CONF |
| + | for i in $dns |
| + | do |
| + | echo adding dns $i |
| + | echo nameserver $i >> $RESOLV_CONF |
| + | done |
| @@ -0,0 +1,7 @@ | |
| + | #!/bin/sh |
| + | # Currently, we only dispatch according to command. However, a more |
| + | # elaborate system might dispatch by command and interface or do some |
| + | # common initialization first, especially if more dhcp event notifications |
| + | # are added. |
| + | |
| + | exec /usr/share/udhcpc/sample.$1 |
| @@ -0,0 +1,39 @@ | |
| + | #!/bin/sh |
| + | |
| + | # udhcpc script edited by Tim Riker <[email protected]> |
| + | |
| + | [ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1 |
| + | |
| + | RESOLV_CONF="/etc/resolv.conf" |
| + | [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" |
| + | [ -n "$subnet" ] && NETMASK="netmask $subnet" |
| + | |
| + | case "$1" in |
| + | deconfig) |
| + | /sbin/ifconfig $interface 0.0.0.0 |
| + | ;; |
| + | |
| + | renew|bound) |
| + | /sbin/ifconfig $interface $ip $BROADCAST $NETMASK |
| + | |
| + | if [ -n "$router" ] ; then |
| + | echo "deleting routers" |
| + | while route del default gw 0.0.0.0 dev $interface ; do |
| + | : |
| + | done |
| + | |
| + | for i in $router ; do |
| + | route add default gw $i dev $interface |
| + | done |
| + | fi |
| + | |
| + | echo -n > $RESOLV_CONF |
| + | [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF |
| + | for i in $dns ; do |
| + | echo adding dns $i |
| + | echo nameserver $i >> $RESOLV_CONF |
| + | done |
| + | ;; |
| + | esac |
| + | |
| + | exit 0 |
| @@ -0,0 +1,116 @@ | |
| + | # Sample udhcpd configuration file (/etc/udhcpd.conf) |
| + | |
| + | # The start and end of the IP lease block |
| + | |
| + | start 192.168.0.20 #default: 192.168.0.20 |
| + | end 192.168.0.254 #default: 192.168.0.254 |
| + | |
| + | |
| + | # The interface that udhcpd will use |
| + | |
| + | interface eth0 #default: eth0 |
| + | |
| + | |
| + | # The maximim number of leases (includes addressesd reserved |
| + | # by OFFER's, DECLINE's, and ARP conficts |
| + | |
| + | #max_leases 254 #default: 254 |
| + | |
| + | |
| + | # If remaining is true (default), udhcpd will store the time |
| + | # remaining for each lease in the udhcpd leases file. This is |
| + | # for embedded systems that cannot keep time between reboots. |
| + | # If you set remaining to no, the absolute time that the lease |
| + | # expires at will be stored in the dhcpd.leases file. |
| + | |
| + | #remaining yes #default: yes |
| + | |
| + | |
| + | # The time period at which udhcpd will write out a dhcpd.leases |
| + | # file. If this is 0, udhcpd will never automatically write a |
| + | # lease file. (specified in seconds) |
| + | |
| + | #auto_time 7200 #default: 7200 (2 hours) |
| + | |
| + | |
| + | # The amount of time that an IP will be reserved (leased) for if a |
| + | # DHCP decline message is received (seconds). |
| + | |
| + | #decline_time 3600 #default: 3600 (1 hour) |
| + | |
| + | |
| + | # The amount of time that an IP will be reserved (leased) for if an |
| + | # ARP conflct occurs. (seconds |
| + | |
| + | #conflict_time 3600 #default: 3600 (1 hour) |
| + | |
| + | |
| + | # How long an offered address is reserved (leased) in seconds |
| + | |
| + | #offer_time 60 #default: 60 (1 minute) |
| + | |
| + | # If a lease to be given is below this value, the full lease time is |
| + | # instead used (seconds). |
| + | |
| + | #min_lease 60 #defult: 60 |
| + | |
| + | |
| + | # The location of the leases file |
| + | |
| + | #lease_file /var/lib/misc/udhcpd.leases #defualt: /var/lib/misc/udhcpd.leases |
| + | |
| + | # The location of the pid file |
| + | #pidfile /var/run/udhcpd.pid #default: /var/run/udhcpd.pid |
| + | |
| + | # Everytime udhcpd writes a leases file, the below script will be called. |
| + | # Useful for writing the lease file to flash every few hours. |
| + | |
| + | #notify_file #default: (no script) |
| + | |
| + | #notify_file dumpleases # <--- usefull for debugging |
| + | |
| + | # The following are bootp specific options, setable by udhcpd. |
| + | |
| + | #siaddr 192.168.0.22 #default: 0.0.0.0 |
| + | |
| + | #sname zorak #default: (none) |
| + | |
| + | #boot_file /var/nfs_root #default: (none) |
| + | |
| + | # The remainer of options are DHCP options and can be specifed with the |
| + | # keyword 'opt' or 'option'. If an option can take multiple items, such |
| + | # as the dns option, they can be listed on the same line, or multiple |
| + | # lines. The only option with a default is 'lease'. |
| + | |
| + | #Examles |
| + | opt dns 192.168.10.2 192.168.10.10 |
| + | option subnet 255.255.255.0 |
| + | opt router 192.168.10.2 |
| + | opt wins 192.168.10.10 |
| + | option dns 129.219.13.81 # appened to above DNS servers for a total of 3 |
| + | option domain local |
| + | option lease 864000 # 10 days of seconds |
| + | |
| + | |
| + | # Currently supported options, for more info, see options.c |
| + | #opt subnet |
| + | #opt timezone |
| + | #opt router |
| + | #opt timesvr |
| + | #opt namesvr |
| + | #opt dns |
| + | #opt logsvr |
| + | #opt cookiesvr |
| + | #opt lprsvr |
| + | #opt bootsize |
| + | #opt domain |
| + | #opt swapsvr |
| + | #opt rootpath |
| + | #opt ipttl |
| + | #opt mtu |
| + | #opt broadcast |
| + | #opt wins |
| + | #opt lease |
| + | #opt ntpsrv |
| + | #opt tftp |
| + | #opt bootfile |
| @@ -0,0 +1,234 @@ | |
| + | /* script.c |
| + | * |
| + | * Functions to call the DHCP client notification scripts |
| + | * |
| + | * Russ Dill <[email protected]> July 2001 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | #include <string.h> |
| + | #include <unistd.h> |
| + | #include <stdio.h> |
| + | #include <stdlib.h> |
| + | #include <sys/socket.h> |
| + | #include <netinet/in.h> |
| + | #include <arpa/inet.h> |
| + | #include <sys/types.h> |
| + | #include <sys/wait.h> |
| + | |
| + | #include "common.h" |
| + | #include "options.h" |
| + | #include "dhcpd.h" |
| + | #include "dhcpc.h" |
| + | #include "script.h" |
| + | |
| + | /* get a rough idea of how long an option will be (rounding up...) */ |
| + | static const int max_option_length[] = { |
| + | [OPTION_IP] = sizeof("255.255.255.255 "), |
| + | [OPTION_IP_PAIR] = sizeof("255.255.255.255 ") * 2, |
| + | [OPTION_STRING] = 1, |
| + | [OPTION_BOOLEAN] = sizeof("yes "), |
| + | [OPTION_U8] = sizeof("255 "), |
| + | [OPTION_U16] = sizeof("65535 "), |
| + | [OPTION_S16] = sizeof("-32768 "), |
| + | [OPTION_U32] = sizeof("4294967295 "), |
| + | [OPTION_S32] = sizeof("-2147483684 "), |
| + | }; |
| + | |
| + | |
| + | static inline int upper_length(int length, int opt_index) |
| + | { |
| + | return max_option_length[opt_index] * |
| + | (length / option_lengths[opt_index]); |
| + | } |
| + | |
| + | |
| + | static int sprintip(char *dest, char *pre, uint8_t *ip) |
| + | { |
| + | return sprintf(dest, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]); |
| + | } |
| + | |
| + | |
| + | /* really simple implementation, just count the bits */ |
| + | static int mton(struct in_addr *mask) |
| + | { |
| + | int i; |
| + | unsigned long bits = ntohl(mask->s_addr); |
| + | /* too bad one can't check the carry bit, etc in c bit |
| + | * shifting */ |
| + | for (i = 0; i < 32 && !((bits >> i) & 1); i++); |
| + | return 32 - i; |
| + | } |
| + | |
| + | |
| + | /* Fill dest with the text of option 'option'. */ |
| + | static void fill_options(char *dest, uint8_t *option, struct dhcp_option *type_p) |
| + | { |
| + | int type, optlen; |
| + | uint16_t val_u16; |
| + | int16_t val_s16; |
| + | uint32_t val_u32; |
| + | int32_t val_s32; |
| + | int len = option[OPT_LEN - 2]; |
| + | |
| + | dest += sprintf(dest, "%s=", type_p->name); |
| + | |
| + | type = type_p->flags & TYPE_MASK; |
| + | optlen = option_lengths[type]; |
| + | for(;;) { |
| + | switch (type) { |
| + | case OPTION_IP_PAIR: |
| + | dest += sprintip(dest, "", option); |
| + | *(dest++) = '/'; |
| + | option += 4; |
| + | optlen = 4; |
| + | case OPTION_IP: /* Works regardless of host byte order. */ |
| + | dest += sprintip(dest, "", option); |
| + | break; |
| + | case OPTION_BOOLEAN: |
| + | dest += sprintf(dest, *option ? "yes" : "no"); |
| + | break; |
| + | case OPTION_U8: |
| + | dest += sprintf(dest, "%u", *option); |
| + | break; |
| + | case OPTION_U16: |
| + | memcpy(&val_u16, option, 2); |
| + | dest += sprintf(dest, "%u", ntohs(val_u16)); |
| + | break; |
| + | case OPTION_S16: |
| + | memcpy(&val_s16, option, 2); |
| + | dest += sprintf(dest, "%d", ntohs(val_s16)); |
| + | break; |
| + | case OPTION_U32: |
| + | memcpy(&val_u32, option, 4); |
| + | dest += sprintf(dest, "%lu", (unsigned long) ntohl(val_u32)); |
| + | break; |
| + | case OPTION_S32: |
| + | memcpy(&val_s32, option, 4); |
| + | dest += sprintf(dest, "%ld", (long) ntohl(val_s32)); |
| + | break; |
| + | case OPTION_STRING: |
| + | memcpy(dest, option, len); |
| + | dest[len] = '\0'; |
| + | return; /* Short circuit this case */ |
| + | } |
| + | option += optlen; |
| + | len -= optlen; |
| + | if (len <= 0) break; |
| + | dest += sprintf(dest, " "); |
| + | } |
| + | } |
| + | |
| + | |
| + | /* put all the parameters into an environment */ |
| + | static char **fill_envp(struct dhcpMessage *packet) |
| + | { |
| + | int num_options = 0; |
| + | int i, j; |
| + | char **envp; |
| + | uint8_t *temp; |
| + | struct in_addr subnet; |
| + | char over = 0; |
| + | |
| + | if (packet == NULL) |
| + | num_options = 0; |
| + | else { |
| + | for (i = 0; dhcp_options[i].code; i++) |
| + | if (get_option(packet, dhcp_options[i].code)) { |
| + | num_options++; |
| + | if (dhcp_options[i].code == DHCP_SUBNET) |
| + | num_options++; /* for mton */ |
| + | } |
| + | if (packet->siaddr) num_options++; |
| + | if ((temp = get_option(packet, DHCP_OPTION_OVER))) |
| + | over = *temp; |
| + | if (!(over & FILE_FIELD) && packet->file[0]) num_options++; |
| + | if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++; |
| + | } |
| + | |
| + | envp = xcalloc(sizeof(char *), num_options + 5); |
| + | j = 0; |
| + | asprintf(&envp[j++], "interface=%s", client_config.interface); |
| + | asprintf(&envp[j++], "%s=%s", "PATH", |
| + | getenv("PATH") ? : "/bin:/usr/bin:/sbin:/usr/sbin"); |
| + | asprintf(&envp[j++], "%s=%s", "HOME", getenv("HOME") ? : "/"); |
| + | |
| + | if (packet == NULL) return envp; |
| + | |
| + | envp[j] = xmalloc(sizeof("ip=255.255.255.255")); |
| + | sprintip(envp[j++], "ip=", (uint8_t *) &packet->yiaddr); |
| + | |
| + | |
| + | for (i = 0; dhcp_options[i].code; i++) { |
| + | if (!(temp = get_option(packet, dhcp_options[i].code))) |
| + | continue; |
| + | envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2], |
| + | dhcp_options[i].flags & TYPE_MASK) + strlen(dhcp_options[i].name) + 2); |
| + | fill_options(envp[j++], temp, &dhcp_options[i]); |
| + | |
| + | /* Fill in a subnet bits option for things like /24 */ |
| + | if (dhcp_options[i].code == DHCP_SUBNET) { |
| + | memcpy(&subnet, temp, 4); |
| + | asprintf(&envp[j++], "mask=%d", mton(&subnet)); |
| + | } |
| + | } |
| + | if (packet->siaddr) { |
| + | envp[j] = xmalloc(sizeof("siaddr=255.255.255.255")); |
| + | sprintip(envp[j++], "siaddr=", (uint8_t *) &packet->siaddr); |
| + | } |
| + | if (!(over & FILE_FIELD) && packet->file[0]) { |
| + | /* watch out for invalid packets */ |
| + | packet->file[sizeof(packet->file) - 1] = '\0'; |
| + | asprintf(&envp[j++], "boot_file=%s", packet->file); |
| + | } |
| + | if (!(over & SNAME_FIELD) && packet->sname[0]) { |
| + | /* watch out for invalid packets */ |
| + | packet->sname[sizeof(packet->sname) - 1] = '\0'; |
| + | asprintf(&envp[j++], "sname=%s", packet->sname); |
| + | } |
| + | return envp; |
| + | } |
| + | |
| + | |
| + | /* Call a script with a par file and env vars */ |
| + | void run_script(struct dhcpMessage *packet, const char *name) |
| + | { |
| + | int pid; |
| + | char **envp, **curr; |
| + | |
| + | if (client_config.script == NULL) |
| + | return; |
| + | |
| + | DEBUG(LOG_INFO, "vforking and execle'ing %s", client_config.script); |
| + | |
| + | envp = fill_envp(packet); |
| + | /* call script */ |
| + | pid = vfork(); |
| + | if (pid) { |
| + | waitpid(pid, NULL, 0); |
| + | for (curr = envp; *curr; curr++) free(*curr); |
| + | free(envp); |
| + | return; |
| + | } else if (pid == 0) { |
| + | /* close fd's? */ |
| + | |
| + | /* exec script */ |
| + | execle(client_config.script, client_config.script, |
| + | name, NULL, envp); |
| + | LOG(LOG_ERR, "script %s failed: %m", client_config.script); |
| + | exit(1); |
| + | } |
| + | } |
| @@ -0,0 +1,6 @@ | |
| + | #ifndef _SCRIPT_H |
| + | #define _SCRIPT_H |
| + | |
| + | extern void run_script(struct dhcpMessage *packet, const char *name); |
| + | |
| + | #endif |
| @@ -0,0 +1,275 @@ | |
| + | /* serverpacket.c |
| + | * |
| + | * Construct and send DHCP server packets |
| + | * |
| + | * Russ Dill <[email protected]> July 2001 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | #include <sys/socket.h> |
| + | #include <netinet/in.h> |
| + | #include <arpa/inet.h> |
| + | #include <string.h> |
| + | #include <time.h> |
| + | |
| + | #include "common.h" |
| + | #include "serverpacket.h" |
| + | #include "dhcpd.h" |
| + | #include "options.h" |
| + | #include "static_leases.h" |
| + | |
| + | /* send a packet to giaddr using the kernel ip stack */ |
| + | static int send_packet_to_relay(struct dhcpMessage *payload) |
| + | { |
| + | DEBUG(LOG_INFO, "Forwarding packet to relay"); |
| + | |
| + | return kernel_packet(payload, server_config.server, SERVER_PORT, |
| + | payload->giaddr, SERVER_PORT); |
| + | } |
| + | |
| + | |
| + | /* send a packet to a specific arp address and ip address by creating our own ip packet */ |
| + | static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcast) |
| + | { |
| + | uint8_t *chaddr; |
| + | uint32_t ciaddr; |
| + | |
| + | if (force_broadcast) { |
| + | DEBUG(LOG_INFO, "broadcasting packet to client (NAK)"); |
| + | ciaddr = INADDR_BROADCAST; |
| + | chaddr = MAC_BCAST_ADDR; |
| + | } else if (payload->ciaddr) { |
| + | DEBUG(LOG_INFO, "unicasting packet to client ciaddr"); |
| + | ciaddr = payload->ciaddr; |
| + | chaddr = payload->chaddr; |
| + | } else if (ntohs(payload->flags) & BROADCAST_FLAG) { |
| + | DEBUG(LOG_INFO, "broadcasting packet to client (requested)"); |
| + | ciaddr = INADDR_BROADCAST; |
| + | chaddr = MAC_BCAST_ADDR; |
| + | } else { |
| + | DEBUG(LOG_INFO, "unicasting packet to client yiaddr"); |
| + | ciaddr = payload->yiaddr; |
| + | chaddr = payload->chaddr; |
| + | } |
| + | return raw_packet(payload, server_config.server, SERVER_PORT, |
| + | ciaddr, CLIENT_PORT, chaddr, server_config.ifindex); |
| + | } |
| + | |
| + | |
| + | /* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */ |
| + | static int send_packet(struct dhcpMessage *payload, int force_broadcast) |
| + | { |
| + | int ret; |
| + | |
| + | if (payload->giaddr) |
| + | ret = send_packet_to_relay(payload); |
| + | else ret = send_packet_to_client(payload, force_broadcast); |
| + | return ret; |
| + | } |
| + | |
| + | |
| + | static void init_packet(struct dhcpMessage *packet, struct dhcpMessage *oldpacket, char type) |
| + | { |
| + | init_header(packet, type); |
| + | packet->xid = oldpacket->xid; |
| + | memcpy(packet->chaddr, oldpacket->chaddr, 16); |
| + | packet->flags = oldpacket->flags; |
| + | packet->giaddr = oldpacket->giaddr; |
| + | packet->ciaddr = oldpacket->ciaddr; |
| + | add_simple_option(packet->options, DHCP_SERVER_ID, server_config.server); |
| + | } |
| + | |
| + | |
| + | /* add in the bootp options */ |
| + | static void add_bootp_options(struct dhcpMessage *packet) |
| + | { |
| + | packet->siaddr = server_config.siaddr; |
| + | if (server_config.sname) |
| + | strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1); |
| + | if (server_config.boot_file) |
| + | strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1); |
| + | } |
| + | |
| + | |
| + | /* send a DHCP OFFER to a DHCP DISCOVER */ |
| + | int sendOffer(struct dhcpMessage *oldpacket) |
| + | { |
| + | struct dhcpMessage packet; |
| + | struct dhcpOfferedAddr *lease = NULL; |
| + | uint32_t req_align, lease_time_align = server_config.lease; |
| + | uint8_t *req, *lease_time; |
| + | struct option_set *curr; |
| + | struct in_addr addr; |
| + | |
| + | uint32_t static_lease_ip; |
| + | |
| + | init_packet(&packet, oldpacket, DHCPOFFER); |
| + | |
| + | static_lease_ip = getIpByMac(server_config.static_leases, oldpacket->chaddr); |
| + | |
| + | /* ADDME: if static, short circuit */ |
| + | if(!static_lease_ip) |
| + | { |
| + | /* the client is in our lease/offered table */ |
| + | if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) { |
| + | if (!lease_expired(lease)) |
| + | lease_time_align = lease->expires - time(0); |
| + | packet.yiaddr = lease->yiaddr; |
| + | |
| + | /* Or the client has a requested ip */ |
| + | } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) && |
| + | |
| + | /* Don't look here (ugly hackish thing to do) */ |
| + | memcpy(&req_align, req, 4) && |
| + | |
| + | /* and the ip is in the lease range */ |
| + | ntohl(req_align) >= ntohl(server_config.start) && |
| + | ntohl(req_align) <= ntohl(server_config.end) && |
| + | |
| + | !static_lease_ip && /* Check that its not a static lease */ |
| + | /* and is not already taken/offered */ |
| + | ((!(lease = find_lease_by_yiaddr(req_align)) || |
| + | |
| + | /* or its taken, but expired */ /* ADDME: or maybe in here */ |
| + | lease_expired(lease)))) { |
| + | packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */ |
| + | |
| + | /* otherwise, find a free IP */ |
| + | } else { |
| + | /* Is it a static lease? (No, because find_address skips static lease) */ |
| + | packet.yiaddr = find_address(0); |
| + | |
| + | /* try for an expired lease */ |
| + | if (!packet.yiaddr) packet.yiaddr = find_address(1); |
| + | } |
| + | |
| + | if(!packet.yiaddr) { |
| + | LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned"); |
| + | return -1; |
| + | } |
| + | |
| + | if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) { |
| + | LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned"); |
| + | return -1; |
| + | } |
| + | |
| + | if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { |
| + | memcpy(&lease_time_align, lease_time, 4); |
| + | lease_time_align = ntohl(lease_time_align); |
| + | if (lease_time_align > server_config.lease) |
| + | lease_time_align = server_config.lease; |
| + | } |
| + | |
| + | /* Make sure we aren't just using the lease time from the previous offer */ |
| + | if (lease_time_align < server_config.min_lease) |
| + | lease_time_align = server_config.lease; |
| + | } |
| + | /* ADDME: end of short circuit */ |
| + | else |
| + | { |
| + | /* It is a static lease... use it */ |
| + | packet.yiaddr = static_lease_ip; |
| + | } |
| + | |
| + | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); |
| + | |
| + | curr = server_config.options; |
| + | while (curr) { |
| + | if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) |
| + | add_option_string(packet.options, curr->data); |
| + | curr = curr->next; |
| + | } |
| + | |
| + | add_bootp_options(&packet); |
| + | |
| + | addr.s_addr = packet.yiaddr; |
| + | LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr)); |
| + | return send_packet(&packet, 0); |
| + | } |
| + | |
| + | |
| + | int sendNAK(struct dhcpMessage *oldpacket) |
| + | { |
| + | struct dhcpMessage packet; |
| + | |
| + | init_packet(&packet, oldpacket, DHCPNAK); |
| + | |
| + | DEBUG(LOG_INFO, "sending NAK"); |
| + | return send_packet(&packet, 1); |
| + | } |
| + | |
| + | |
| + | int sendACK(struct dhcpMessage *oldpacket, uint32_t yiaddr) |
| + | { |
| + | struct dhcpMessage packet; |
| + | struct option_set *curr; |
| + | uint8_t *lease_time; |
| + | uint32_t lease_time_align = server_config.lease; |
| + | struct in_addr addr; |
| + | |
| + | init_packet(&packet, oldpacket, DHCPACK); |
| + | packet.yiaddr = yiaddr; |
| + | |
| + | if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) { |
| + | memcpy(&lease_time_align, lease_time, 4); |
| + | lease_time_align = ntohl(lease_time_align); |
| + | if (lease_time_align > server_config.lease) |
| + | lease_time_align = server_config.lease; |
| + | else if (lease_time_align < server_config.min_lease) |
| + | lease_time_align = server_config.lease; |
| + | } |
| + | |
| + | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align)); |
| + | |
| + | curr = server_config.options; |
| + | while (curr) { |
| + | if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) |
| + | add_option_string(packet.options, curr->data); |
| + | curr = curr->next; |
| + | } |
| + | |
| + | add_bootp_options(&packet); |
| + | |
| + | addr.s_addr = packet.yiaddr; |
| + | LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(addr)); |
| + | |
| + | if (send_packet(&packet, 0) < 0) |
| + | return -1; |
| + | |
| + | add_lease(packet.chaddr, packet.yiaddr, lease_time_align); |
| + | |
| + | return 0; |
| + | } |
| + | |
| + | |
| + | int send_inform(struct dhcpMessage *oldpacket) |
| + | { |
| + | struct dhcpMessage packet; |
| + | struct option_set *curr; |
| + | |
| + | init_packet(&packet, oldpacket, DHCPACK); |
| + | |
| + | curr = server_config.options; |
| + | while (curr) { |
| + | if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) |
| + | add_option_string(packet.options, curr->data); |
| + | curr = curr->next; |
| + | } |
| + | |
| + | add_bootp_options(&packet); |
| + | |
| + | return send_packet(&packet, 0); |
| + | } |
| @@ -0,0 +1,12 @@ | |
| + | #ifndef _SERVERPACKET_H |
| + | #define _SERVERPACKET_H |
| + | |
| + | #include "packet.h" |
| + | |
| + | int sendOffer(struct dhcpMessage *oldpacket); |
| + | int sendNAK(struct dhcpMessage *oldpacket); |
| + | int sendACK(struct dhcpMessage *oldpacket, uint32_t yiaddr); |
| + | int send_inform(struct dhcpMessage *oldpacket); |
| + | |
| + | |
| + | #endif |
| @@ -0,0 +1,84 @@ | |
| + | /* signalpipe.c |
| + | * |
| + | * Signal pipe infrastructure. A reliable way of delivering signals. |
| + | * |
| + | * Russ Dill <[email protected]> December 2003 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | #include <unistd.h> |
| + | #include <fcntl.h> |
| + | #include <signal.h> |
| + | #include <sys/types.h> |
| + | #include <sys/socket.h> |
| + | #include <sys/select.h> |
| + | |
| + | |
| + | #include "signalpipe.h" |
| + | #include "common.h" |
| + | |
| + | static int signal_pipe[2]; |
| + | |
| + | static void signal_handler(int sig) |
| + | { |
| + | if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) |
| + | DEBUG(LOG_ERR, "Could not send signal: %m"); |
| + | } |
| + | |
| + | |
| + | /* Call this before doing anything else. Sets up the socket pair |
| + | * and installs the signal handler */ |
| + | void udhcp_sp_setup(void) |
| + | { |
| + | socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe); |
| + | fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC); |
| + | fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC); |
| + | signal(SIGUSR1, signal_handler); |
| + | signal(SIGUSR2, signal_handler); |
| + | signal(SIGTERM, signal_handler); |
| + | } |
| + | |
| + | |
| + | /* Quick little function to setup the rfds. Will return the |
| + | * max_fd for use with select. Limited in that you can only pass |
| + | * one extra fd */ |
| + | int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) |
| + | { |
| + | FD_ZERO(rfds); |
| + | FD_SET(signal_pipe[0], rfds); |
| + | if (extra_fd >= 0) { |
| + | fcntl(extra_fd, F_SETFD, FD_CLOEXEC); |
| + | FD_SET(extra_fd, rfds); |
| + | } |
| + | return signal_pipe[0] > extra_fd ? signal_pipe[0] : extra_fd; |
| + | } |
| + | |
| + | |
| + | /* Read a signal from the signal pipe. Returns 0 if there is |
| + | * no signal, -1 on error (and sets errno appropriately), and |
| + | * your signal on success */ |
| + | int udhcp_sp_read(fd_set *rfds) |
| + | { |
| + | int sig; |
| + | |
| + | if (!FD_ISSET(signal_pipe[0], rfds)) |
| + | return 0; |
| + | |
| + | if (read(signal_pipe[0], &sig, sizeof(sig)) < 0) |
| + | return -1; |
| + | |
| + | return sig; |
| + | } |
| @@ -0,0 +1,22 @@ | |
| + | /* signalpipe.h |
| + | * |
| + | * Russ Dill <[email protected]> December 2003 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | void udhcp_sp_setup(void); |
| + | int udhcp_sp_fd_set(fd_set *rfds, int extra_fd); |
| + | int udhcp_sp_read(fd_set *rfds); |
| @@ -0,0 +1,135 @@ | |
| + | /* |
| + | * socket.c -- DHCP server client/server socket creation |
| + | * |
| + | * udhcp client/server |
| + | * Copyright (C) 1999 Matthew Ramsay <[email protected]> |
| + | * Chris Trew <[email protected]> |
| + | * |
| + | * Rewrite by Russ Dill <[email protected]> July 2001 |
| + | * |
| + | * This program is free software; you can redistribute it and/or modify |
| + | * it under the terms of the GNU General Public License as published by |
| + | * the Free Software Foundation; either version 2 of the License, or |
| + | * (at your option) any later version. |
| + | * |
| + | * This program is distributed in the hope that it will be useful, |
| + | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + | * GNU General Public License for more details. |
| + | * |
| + | * You should have received a copy of the GNU General Public License |
| + | * along with this program; if not, write to the Free Software |
| + | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| + | */ |
| + | |
| + | #include <sys/types.h> |
| + | #include <sys/socket.h> |
| + | #include <sys/ioctl.h> |
| + | #include <netinet/in.h> |
| + | #include <unistd.h> |
| + | #include <string.h> |
| + | #include <arpa/inet.h> |
| + | #include <net/if.h> |
| + | #include <errno.h> |
| + | #include <features.h> |
| + | #if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || defined _NEWLIB_VERSION |
| + | #include <netpacket/packet.h> |
| + | #include <net/ethernet.h> |
| + | #else |
| + | #include <asm/types.h> |
| + | #include <linux/if_packet.h> |
| + | #include <linux/if_ether.h> |
| + | #endif |
| + | |
| + | #include "common.h" |
| + | #include "socket.h" |
| + | |
| + | int read_interface(char *interface, int *ifindex, uint32_t *addr, uint8_t *arp) |
| + | { |
| + | int fd; |
| + | struct ifreq ifr; |
| + | struct sockaddr_in *our_ip; |
| + | |
| + | memset(&ifr, 0, sizeof(struct ifreq)); |
| + | if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) { |
| + | ifr.ifr_addr.sa_family = AF_INET; |
| + | strcpy(ifr.ifr_name, interface); |
| + | |
| + | if (addr) { |
| + | if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { |
| + | our_ip = (struct sockaddr_in *) &ifr.ifr_addr; |
| + | *addr = our_ip->sin_addr.s_addr; |
| + | DEBUG(LOG_INFO, "%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr)); |
| + | } else { |
| + | LOG(LOG_ERR, "SIOCGIFADDR failed, is the interface up and configured?: %m"); |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | } |
| + | |
| + | if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) { |
| + | DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex); |
| + | *ifindex = ifr.ifr_ifindex; |
| + | } else { |
| + | LOG(LOG_ERR, "SIOCGIFINDEX failed!: %m"); |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) { |
| + | memcpy(arp, ifr.ifr_hwaddr.sa_data, 6); |
| + | DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x", |
| + | arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]); |
| + | } else { |
| + | LOG(LOG_ERR, "SIOCGIFHWADDR failed!: %m"); |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | } else { |
| + | LOG(LOG_ERR, "socket failed!: %m"); |
| + | return -1; |
| + | } |
| + | close(fd); |
| + | return 0; |
| + | } |
| + | |
| + | |
| + | int listen_socket(uint32_t ip, int port, char *inf) |
| + | { |
| + | struct ifreq interface; |
| + | int fd; |
| + | struct sockaddr_in addr; |
| + | int n = 1; |
| + | |
| + | DEBUG(LOG_INFO, "Opening listen socket on 0x%08x:%d %s", ip, port, inf); |
| + | if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { |
| + | DEBUG(LOG_ERR, "socket call failed: %m"); |
| + | return -1; |
| + | } |
| + | |
| + | memset(&addr, 0, sizeof(addr)); |
| + | addr.sin_family = AF_INET; |
| + | addr.sin_port = htons(port); |
| + | addr.sin_addr.s_addr = ip; |
| + | |
| + | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) { |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *) &n, sizeof(n)) == -1) { |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | |
| + | strncpy(interface.ifr_name, inf, IFNAMSIZ); |
| + | if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,(char *)&interface, sizeof(interface)) < 0) { |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | |
| + | if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) { |
| + | close(fd); |
| + | return -1; |
| + | } |
| + | |
| + | return fd; |
| + | } |
| @@ -0,0 +1,8 @@ | |
| + | /* socket.h */ |
| + | #ifndef _SOCKET_H |
| + | #define _SOCKET_H |
| + | |
| + | int read_interface(char *interface, int *ifindex, uint32_t *addr, uint8_t *arp); |
| + | int listen_socket(uint32_t ip, int port, char *inf); |
| + | |
| + | #endif |
| @@ -0,0 +1,119 @@ | |
| + | /* |
| + | * static_leases.c -- Couple of functions to assist with storing and |
| + | * retrieving data for static leases |
| + | * |
| + | * Wade Berrier <[email protected]> September 2004 |
| + | * |
| + | */ |
| + | |
| + | |
| + | #include <stdlib.h> |
| + | #include <stdio.h> |
| + | #include <string.h> |
| + | |
| + | #include "static_leases.h" |
| + | #include "dhcpd.h" |
| + | |
| + | /* Takes the address of the pointer to the static_leases linked list, |
| + | * Address to a 6 byte mac address |
| + | * Address to a 4 byte ip address */ |
| + | int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip) |
| + | { |
| + | |
| + | struct static_lease *cur; |
| + | struct static_lease *new_static_lease; |
| + | |
| + | /* Build new node */ |
| + | new_static_lease = xmalloc(sizeof(struct static_lease)); |
| + | new_static_lease->mac = mac; |
| + | new_static_lease->ip = ip; |
| + | new_static_lease->next = NULL; |
| + | |
| + | /* If it's the first node to be added... */ |
| + | if(*lease_struct == NULL) |
| + | { |
| + | *lease_struct = new_static_lease; |
| + | } |
| + | else |
| + | { |
| + | cur = *lease_struct; |
| + | while(cur->next != NULL) |
| + | { |
| + | cur = cur->next; |
| + | } |
| + | |
| + | cur->next = new_static_lease; |
| + | } |
| + | |
| + | return 1; |
| + | |
| + | } |
| + | |
| + | /* Check to see if a mac has an associated static lease */ |
| + | uint32_t getIpByMac(struct static_lease *lease_struct, void *arg) |
| + | { |
| + | uint32_t return_ip; |
| + | struct static_lease *cur = lease_struct; |
| + | uint8_t *mac = arg; |
| + | |
| + | return_ip = 0; |
| + | |
| + | while(cur != NULL) |
| + | { |
| + | /* If the client has the correct mac */ |
| + | if(memcmp(cur->mac, mac, 6) == 0) |
| + | { |
| + | return_ip = *(cur->ip); |
| + | } |
| + | |
| + | cur = cur->next; |
| + | } |
| + | |
| + | return return_ip; |
| + | |
| + | } |
| + | |
| + | /* Check to see if an ip is reserved as a static ip */ |
| + | uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip) |
| + | { |
| + | struct static_lease *cur = lease_struct; |
| + | |
| + | uint32_t return_val = 0; |
| + | |
| + | while(cur != NULL) |
| + | { |
| + | /* If the client has the correct ip */ |
| + | if(*cur->ip == ip) |
| + | return_val = 1; |
| + | |
| + | cur = cur->next; |
| + | } |
| + | |
| + | return return_val; |
| + | |
| + | } |
| + | |
| + | #ifdef UDHCP_DEBUG |
| + | /* Print out static leases just to check what's going on */ |
| + | /* Takes the address of the pointer to the static_leases linked list */ |
| + | void printStaticLeases(struct static_lease **arg) |
| + | { |
| + | /* Get a pointer to the linked list */ |
| + | struct static_lease *cur = *arg; |
| + | |
| + | while(cur != NULL) |
| + | { |
| + | /* printf("PrintStaticLeases: Lease mac Address: %x\n", cur->mac); */ |
| + | printf("PrintStaticLeases: Lease mac Value: %x\n", *(cur->mac)); |
| + | /* printf("PrintStaticLeases: Lease ip Address: %x\n", cur->ip); */ |
| + | printf("PrintStaticLeases: Lease ip Value: %x\n", *(cur->ip)); |
| + | |
| + | cur = cur->next; |
| + | } |
| + | |
| + | |
| + | } |
| + | #endif |
| + | |
| + | |
| + | |
| @@ -0,0 +1,25 @@ | |
| + | /* static_leases.h */ |
| + | #ifndef _STATIC_LEASES_H |
| + | #define _STATIC_LEASES_H |
| + | |
| + | #include "dhcpd.h" |
| + | |
| + | /* Config file will pass static lease info to this function which will add it |
| + | * to a data structure that can be searched later */ |
| + | int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip); |
| + | |
| + | /* Check to see if a mac has an associated static lease */ |
| + | uint32_t getIpByMac(struct static_lease *lease_struct, void *arg); |
| + | |
| + | /* Check to see if an ip is reserved as a static ip */ |
| + | uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip); |
| + | |
| + | #ifdef UDHCP_DEBUG |
| + | /* Print out static leases just to check what's going on */ |
| + | void printStaticLeases(struct static_lease **lease_struct); |
| + | #endif |
| + | |
| + | #endif |
| + | |
| + | |
| + | |
| @@ -0,0 +1,208 @@ | |
| + | .TH UDHCPC 8 2001-09-26 GNU/Linux "GNU/Linux Administrator's Manual" |
| + | .SH NAME |
| + | udhcpc \- very small DHCP client |
| + | .SH SYNOPSIS |
| + | .B udhcpc |
| + | .RI [ OPTION ]... |
| + | .SH DESCRIPTION |
| + | The udhcp client negotiates a lease with the DHCP server and |
| + | executes a script when it is obtained or lost. |
| + | .SH OPTIONS |
| + | .TP |
| + | .BI \-c\ CLIENTID ,\ \-\-clientid= CLIENTID |
| + | Send the client identifier |
| + | .IR CLIENTID . |
| + | .TP |
| + | .BR -f ,\ \-\-foreground |
| + | Do not fork after obtaining a lease. |
| + | .TP |
| + | .BI \-H\ HOSTNAME ,\ \-\-hostname= HOSTNAME |
| + | Send the client hostname |
| + | .IR HOSTNAME . |
| + | .TP |
| + | .BI \-h\ HOSTNAME |
| + | Alias for -H |
| + | .IR HOSTNAME . |
| + | .TP |
| + | .BI \-i\ INTERFACE ,\ \-\-interface= INTERFACE |
| + | Configure |
| + | .IR INTERFACE . |
| + | .TP |
| + | .BR -n ,\ \-\-now |
| + | Exit with failure if a lease cannot be obtained. |
| + | .TP |
| + | .BI \-p\ FILE ,\ \-\-pidfile= FILE |
| + | Write the process ID of the daemon to |
| + | .IR FILE . |
| + | .TP |
| + | .BR -q ,\ \-\-quit |
| + | Exit after obtaining a lease. |
| + | .TP |
| + | .BI \-r\ ADDRESS ,\ \-\-request= ADDRESS |
| + | Request IP address |
| + | .IR ADDRESS . |
| + | .TP |
| + | .BI \-s\ FILE ,\ \-\-script= FILE |
| + | Use script |
| + | .IR FILE . |
| + | .TP |
| + | .BR -v ,\ \-\-version |
| + | Display version. |
| + | .SH USAGE |
| + | When an event occurs, |
| + | .B udhcpc |
| + | executes a script. There are four possible arguments to this |
| + | script: |
| + | .TP |
| + | .B deconfig |
| + | .B deconfig |
| + | is used when |
| + | .B udhcpc |
| + | starts, and when a lease is lost. The script should put the |
| + | interface in an up, but deconfigured, state. |
| + | .TP |
| + | .B bound |
| + | .B bound |
| + | is used when |
| + | .B udhcpc |
| + | moves from an unbound to a bound state. The script should |
| + | configure the interface and set any other relevant parameters |
| + | (e.g., default gateway, dns server, etc.). |
| + | .TP |
| + | .B renew |
| + | .B renew |
| + | is used when |
| + | .B udhcpc |
| + | when a lease is renewed. The interface is already |
| + | configured, so the IP address will not change. Other parameters |
| + | (e.g., default gateway, subnet mask, dns server) may. |
| + | .TP |
| + | .B nak |
| + | .B nak |
| + | is used when |
| + | .B udhcpc |
| + | receieves a NAK packet from the server. The |
| + | enviromental variable |
| + | .B $message |
| + | will contain the reason for the |
| + | NAK message if the server included one. Processing this message |
| + | is optional, as the script will also be called with deconfig if |
| + | need be. |
| + | .PP |
| + | Parameters are passed to the script via the following environment |
| + | variables: |
| + | .TP |
| + | .B HOME |
| + | The inherited HOME, or "/" if it is unset. |
| + | .TP |
| + | .B PATH |
| + | The inherited PATH, or "/bin:/usr/bin:/sbin:/usr/sbin" if it is |
| + | unset. |
| + | .TP |
| + | .B interface |
| + | The interface. |
| + | .TP |
| + | .B ip |
| + | The client IP address. |
| + | .TP |
| + | .B siaddr |
| + | The BOOTP next server option. |
| + | .TP |
| + | .B sname |
| + | The BOOTP server name option. |
| + | .TP |
| + | .B boot_file |
| + | The BOOTP boot file option. |
| + | .TP |
| + | .B subnet |
| + | The subnet mask. |
| + | .TP |
| + | .B timezone |
| + | The timezone offset from UTC in seconds. |
| + | .TP |
| + | .B router |
| + | The list of routers. |
| + | .TP |
| + | .B timesvr |
| + | The list of time servers. |
| + | .TP |
| + | .B namesvr |
| + | The list of IEN 116 name servers. |
| + | .TP |
| + | .B dns |
| + | The list of DNS servers. |
| + | .TP |
| + | .B logsvr |
| + | The list of MIT-LCS UDP log servers. |
| + | .TP |
| + | .B cookiesvr |
| + | The list of RFC 865 cookie servers. |
| + | .TP |
| + | .B lprsvr |
| + | The list of LPR servers. |
| + | .TP |
| + | .B hostname |
| + | The host name. |
| + | .TP |
| + | .B bootsize |
| + | The length in 512-octet blocks of the bootfile. |
| + | .TP |
| + | .B domain |
| + | The domain name of the network. |
| + | .TP |
| + | .B swapsvr |
| + | The client's swap server. |
| + | .TP |
| + | .B rootpath |
| + | The path of the client's root dist. |
| + | .TP |
| + | .B ipttl |
| + | The TTL. |
| + | .TP |
| + | .B mtu |
| + | The MTU. |
| + | .TP |
| + | .B broadcast |
| + | The broadcast address. |
| + | .TP |
| + | .B ntpsrv |
| + | The list of NTP servers. |
| + | .TP |
| + | .B wins |
| + | The list of WINS servers. |
| + | .TP |
| + | .B lease |
| + | The lease time in seconds. |
| + | .TP |
| + | .B dhcptype |
| + | The DHCP message type (safely ignored). |
| + | .TP |
| + | .B serverid |
| + | The server IP address. |
| + | .TP |
| + | .B message |
| + | Reason for a DHCPNAK. |
| + | .TP |
| + | .B tftp |
| + | The TFTP server name. |
| + | .TP |
| + | .B bootfile |
| + | The bootfile name. |
| + | .SH FILES |
| + | .TP |
| + | .I /usr/share/udhcpc/default.script |
| + | Script run when leases are obtained or lost. |
| + | .SH NOTES |
| + | .B udhcpc |
| + | responds to the following signals: |
| + | .TP |
| + | .B SIGUSR1 |
| + | This signal causes |
| + | .B udhcpc |
| + | to renew the current lease or, if it does not have one, obtain a |
| + | new lease. |
| + | .TP |
| + | .B SIGUSR2 |
| + | This signal caused |
| + | .B udhcpc |
| + | to release the current lease. |
| @@ -0,0 +1,17 @@ | |
| + | .TH UDHCPD 8 2001-09-27 GNU/Linux "GNU/Linux Administrator's Manual" |
| + | .SH NAME |
| + | udhcpd \- very small DHCP server |
| + | .SH SYNOPSIS |
| + | .B udhcpd |
| + | .SH DESCRIPTION |
| + | The udhcp server negotiates leases with DHCP clients. |
| + | .SH FILES |
| + | .TP |
| + | .I /etc/udhcpd.conf |
| + | Configuration file. |
| + | .TP |
| + | .I /var/lib/misc/udhcpd.leases |
| + | Lease information file. |
| + | .SH SEE ALSO |
| + | .BR dumpleases (1), |
| + | .BR udhcpd.conf (8). |
| @@ -0,0 +1,164 @@ | |
| + | .TH UDHCPD.CONF 5 2001-09-26 GNU/Linux "GNU/Linux Administrator's Manual" |
| + | .SH NAME |
| + | udhcpd.conf \- udhcp server configuration file |
| + | .SH DESCRIPTION |
| + | The file |
| + | .I /etc/udhcpd.conf |
| + | contains configuration information specific to the udhcp server. |
| + | It should contain one configuration keyword per line, followed by |
| + | appropriate configuration information. |
| + | .SH OPTIONS |
| + | .TP |
| + | .BI start\ ADDRESS |
| + | The starting address of the IP lease block is |
| + | .IR ADDRESS . |
| + | The default is |
| + | .BR 192.168.0.20 . |
| + | .TP |
| + | .BI end\ ADDRESS |
| + | The ending address of the IP lease block is |
| + | .IR ADDRESS . |
| + | The default is |
| + | .BR 192.168.0.254 . |
| + | .TP |
| + | .BI interface\ INTERFACE |
| + | The udhcp server should listen on |
| + | .IR INTERFACE . |
| + | The default is |
| + | .BR eth0 . |
| + | .TP |
| + | .BI max_leases\ LEASES |
| + | Offer at most |
| + | .I LEASES |
| + | leases (including those reserved by OFFERs, DECLINEs, and ARP |
| + | conflicts). The default is |
| + | .BR 254 . |
| + | .TP |
| + | .BI remaining\ REMAINING |
| + | If |
| + | .I REMAINING |
| + | is |
| + | .BR yes , |
| + | store the time remaining for each lease. If it is |
| + | .BR no , |
| + | store the expiration time for each lease. The default is |
| + | .BR yes . |
| + | .TP |
| + | .BI auto_time\ SECONDS |
| + | Write the lease information to a file every |
| + | .I SECONDS |
| + | seconds. The default is |
| + | .BR 7200 . |
| + | .TP |
| + | .BI decline_time\ SECONDS |
| + | Reserve an IP for |
| + | .I SECONDS |
| + | seconds if a DHCP decline message is received. The default is |
| + | .BR 3600 . |
| + | .TP |
| + | .BI conflict_time\ SECONDS |
| + | Reserve an IP for |
| + | .I SECONDS |
| + | seconds if an ARP conflict occurs. The default is |
| + | .BR 3600 . |
| + | .TP |
| + | .BI offer_time\ SECONDS |
| + | Reserve an IP for |
| + | .I SECONDS |
| + | seconds if it is offered. The default is |
| + | .BR 60 . |
| + | .TP |
| + | .BI min_lease\ SECONDS |
| + | Reserve an IP for the full lease time if the lease to be given is less than |
| + | .I SECONDS |
| + | seconds. The default is |
| + | .BR 60 . |
| + | .TP |
| + | .BI lease_file\ FILE |
| + | Write the lease information to |
| + | .IR FILE . |
| + | The default is |
| + | .BR /var/lib/misc/udhcpd.leases . |
| + | .TP |
| + | .BI pidfile\ FILE |
| + | Write the process ID to |
| + | .IR FILE . |
| + | The default is |
| + | .BR /var/run/udhcpd.pid . |
| + | .TP |
| + | .BI notify_file\ FILE |
| + | Execute |
| + | .I FILE |
| + | after the lease information is written. By default, no file is executed. |
| + | .TP |
| + | .BI siaddr\ ADDRESS |
| + | BOOTP specific option. The default is |
| + | .BR 0.0.0.0 . |
| + | .TP |
| + | .BI sname\ NAME |
| + | BOOTP specific option. There is no default. |
| + | .TP |
| + | .BI boot_file\ FILE |
| + | BOOTP specific option. There is no default. |
| + | .TP |
| + | .BI option\ OPTION |
| + | DHCP specific option. |
| + | .RS |
| + | .TP |
| + | .BI subnet\ ADDRESS |
| + | .TP |
| + | .BI timezone\ OFFSET |
| + | .TP |
| + | .BI router\ ADDRESS... |
| + | .TP |
| + | .BI timesvr\ ADDRESS... |
| + | .TP |
| + | .BI namesvr\ ADDRESS... |
| + | .TP |
| + | .BI dns\ ADDRESS... |
| + | .TP |
| + | .BI logsvr\ ADDRESS... |
| + | .TP |
| + | .BI cookiesvr\ ADDRESS... |
| + | .TP |
| + | .BI lprsvr\ ADDRESS... |
| + | .TP |
| + | .BI hostname\ HOSTNAME |
| + | .TP |
| + | .BI bootsize\ SIZE |
| + | .TP |
| + | .BI domain\ DOMAIN |
| + | .TP |
| + | .BI swapsvr\ ADDRESS |
| + | .TP |
| + | .BI rootpath\ PATH |
| + | .TP |
| + | .BI ipttl\ TTL |
| + | .TP |
| + | .BI mtu\ MTU |
| + | .TP |
| + | .BI broadcast\ ADDRESS |
| + | .TP |
| + | .BI ntpsrv\ ADDRESS... |
| + | .TP |
| + | .BI wins\ ADDRESS... |
| + | .TP |
| + | .BI requestip\ ADDRESS |
| + | .TP |
| + | .BI lease\ SECONDS |
| + | .TP |
| + | .BI dhcptype\ TYPE |
| + | .TP |
| + | .BI serverid\ ADDRESS |
| + | .TP |
| + | .BI tftp\ FILE |
| + | .TP |
| + | .BI bootfile\ FILE |
| + | The default for |
| + | .B lease |
| + | is |
| + | .BR 864000 . |
| + | There are no defaults for the other options. |
| + | .RE |
| + | .SH SEE ALSO |
| + | .BR udhcpd (8). |
| @@ -0,0 +1,6 @@ | |
| + | #ifndef _UDHCP_VERSION_H |
| + | #define _UDHCP_VERSION_H |
| + | |
| + | #define VERSION "0.9.9-pre" |
| + | |
| + | #endif |