diff --git a/ChangeLog b/ChangeLog index 144f33118e..94bccc6c91 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2004-11-15 Dan Williams + + Major rework of link detection code. We now use DHCP + as part of the link detection which proves to be much more robust, + and also supports Open System authentication for wireless networks. + + We no longer use external DHCP client programs. Instead, we use + our own DHCP client, based on substantially reworked bits of 'dhcpcd' + which was written by: + Yoichi Hariguchi + Sergei Viznyuk + http://www.phystech.com/download/ + It resides in the "dhcpcd" directory and was refactored into a general + purpose DHCP client library by me. + + Also misc fixes (CPPFLAGS->AM_CPPFLAGS, move some stuff around), + move src/backends/NetworkManagerSystem.h -> src/NetworkManagerSystem.h + 2004-11-15 Dan Williams Patch from Tom Parker : diff --git a/Makefile.am b/Makefile.am index 848f40494c..ead81dffa6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = src dispatcher-daemon $(notification_icon_dir) info-daemon initscript test po +SUBDIRS = src dispatcher-daemon $(notification_icon_dir) info-daemon initscript test dhcpcd po EXTRA_DIST = CONTRIBUTING NetworkManager.pc.in NetworkManager.h diff --git a/configure.in b/configure.in index 8282ab131c..81ea97aba3 100644 --- a/configure.in +++ b/configure.in @@ -5,11 +5,34 @@ AM_INIT_AUTOMAKE([subdir-objects]) AM_CONFIG_HEADER(config.h) +dnl +dnl Require programs +dnl AC_PROG_CC AM_PROG_CC_C_O - +AC_PROG_INSTALL AC_PROG_LIBTOOL +dnl +dnl Required headers +dnl +AC_HEADER_STDC +AC_CHECK_HEADERS(fcntl.h paths.h sys/ioctl.h sys/time.h syslog.h unistd.h) + +dnl +dnl Checks for typedefs, structures, and compiler characteristics. +dnl +AC_TYPE_MODE_T +AC_TYPE_PID_T +AC_HEADER_TIME + +dnl +dnl Checks for library functions. +dnl +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MEMCMP +AC_CHECK_FUNCS(select socket uname) + GETTEXT_PACKAGE=NetworkManager AC_SUBST(GETTEXT_PACKAGE) AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package]) @@ -170,6 +193,7 @@ dispatcher-daemon/Makefile info-daemon/Makefile panel-applet/Makefile panel-applet/icons/Makefile +dhcpcd/Makefile test/Makefile initscript/Makefile initscript/RedHat/Makefile diff --git a/dhcpcd/AUTHORS b/dhcpcd/AUTHORS new file mode 100644 index 0000000000..d3d4cf09b2 --- /dev/null +++ b/dhcpcd/AUTHORS @@ -0,0 +1,2 @@ +Copyright (C) 1996 - 1997 Yoichi Hariguchi +Copyright (C) January, 1998 Sergei Viznyuk diff --git a/dhcpcd/COPYING b/dhcpcd/COPYING new file mode 100644 index 0000000000..d60c31a97a --- /dev/null +++ b/dhcpcd/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 + + 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. + + + Copyright (C) + + 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 + + +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) year 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. + + , 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. diff --git a/dhcpcd/ChangeLog b/dhcpcd/ChangeLog new file mode 100644 index 0000000000..5c237322df --- /dev/null +++ b/dhcpcd/ChangeLog @@ -0,0 +1,794 @@ +12/31/02 - v.1.3.22-pl4 + Peter Poeml submitted patches to: + 1. enable support for Token Ring. + 2. disable second DHCP_DISCOVER message. S.V - added "-S" option to dhcpcd command + line to make second DHCP_DISCOVER message optional. + 3. Make dhcpcd write to the console if syslogd is not running only with + "-d" DebugFlag. + Robert Whaley submitted patch to elimited potential + race condition between setting up the setjmp for dhcpReboot and the sigalarm handler. + Ian Sharpe submitted patch to handle situations + with DHCP server changing lease or T1,T2 times from renewal to renewal. + Jamey Hicks pointed out the setting of the netmask for + static route still doesn't always work correctly. Wrote "getgenmask" function + to try to deduce the netmask for static routes - S.V. + Per-Olof Pettersson suggested "-G" option to prevent + dhcpcd from installing default routes. Expanded "-G" to include optional + [gateway] parameter for ip address of default router - S.V. The "-G" option + has also been added by Peter Poeml in one of the patches he sent. + S.V.- moved parts of the code from client.c into cache.c and dhcpconfig.c files. + +09/30/02 - v.1.3.22-pl3 + Duke Cho submitted patch for dhcpSendAndRecv() to scan + for begining of IP header in the received Ethernet frame rather than assume + it begins right after Ethernet header. It made dhcpcd work for ARM7TDMI cored SoC + boards. + Marc Beuchat submitted patch to open 0,1,2 file descriptors + at the start of dhcpcd if they are closed as in a case when dhcpcd starts from + pcmcia-cs network script. + +09/21/02 - v.1.3.22-pl2 + James Hicks submitted patch to set the netmask properly + for static routes provided by the DHCP server. + Michal Dobes pointed out there could be situation with + many dhcpcd clients starting at the same time on different machines on the + same network in which case they will generate the DHCP messages with the + same XID and potentially configure the same IP addresses. Fixed by + including CLientHwAddr (MAC address) into the seed for srandom(). -S.V. + David Fallon recomended changing sbindir to = ${exec_prefix}/sbin + rather than ${prefix} in Makefile.am. Also changed docdir=/usr/doc. -S.V. + Henning Spruth suggested replacing + getuid() call with geteuid() in dhcpcd.c to enable setuid tools + to launch dhcpcd. + David Oleszkiewicz pointed out "logger" should + be used in dhcpcd.exe script instead of direct write to a log files. + Tobias Blomberg pointed out to a bug report at + https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=65515 + what appears to be dhcpcd cache overriding command line options -I and -i. + The related problem has been also reported by Øyvind Bakksjø + . Fixed by calling clientIDsetup and classIDsetup + even after successfull cache read. + Kosbar, Kurt Louis submitted patch to fix a case of + dhcpcd client crash because of some DHCP server sending no dhcpMessageType + field in DHCP message. + Simon Kelley pointed out at security bug in dhcpcd + related to *.info file. A malicios administrator of untrusted DHCP server + may execute any command with root privileges on DHCP client machine by + sending the command enclosed in shell metacharacters in one of DHCP server + provided options. Fixed by enclosing all strings in *.info file into single + quotes and replacing any single quotes found in DHCP option strings + with space. - S.V. + +01/20/02 - v.1.3.22-pl1 + S.V. - added support for virtual interfaces (eth0:1, eth1:2, etc) + inside dhcpcd itself. The "external" support (with external script + using *.info file) has been added in v.1.3.22-pl0. + +01/19/02 - v.1.3.22-pl0 + Scott Gifford and Victor McSmith + suggested letting custom scripts instead of dhcpcd do all the + interface configuration work using DHCP info secured by dhcpcd + and stored in the *.info file. + Pramod Immaneni suggested adding -L option to + dhcpcd to enable writing configuration information into a given *.info + file to be later used by other scripts. He also suggested modifying + -T option to save configuration information rather than just exiting after + DHCP negotiation sequence. + S.V. - the above proposals inspired the following changes to dhcpcd: + + 1. "-L " option has been added. Dhcpcd will store *.info, + *.cache files under rather than default /etc/dhcpc. + 2. *.pid file has moved from under /var/run to under + (default /etc/dhcpc) subdirectory. + 3. -T option behaviour has been modified to include writing + *.info, *.cache, *.pid files under , and executing + *.exe script in the same manner as without -T option. + Now with -T option dhcpcd will do everything except actually + configuring interface or changing any files under /etc. + Also now with -T option dhcpcd will not exit at the end of DHCP + negotiation sequence but will go into background and attempt + to renew the lease as usual. + -T option in conjunction with -L and -I will + enable users to negotiate/renew multiple IP addresses using the same + dummy interface. + It should also enable configuration of virtual interfaces. + 4. /dhcpcd.exe script calling convention has changed. Now + dhcpcd will pass the path to *.info file as first argument and "up/down/new" + keyword as second argument. The third argument is optional + debugFlag "-d" passed from dhcpcd command line. See sample dhcpcd.exe + script supplied with distribution. + 5. "-c " option has been given second life and its behaviour + has slightly changed. Now script will be executed instead of + default /dhcpcd.exe and in the same manner as + /dhcpcd.exe script (see Item 4 above). + 6. The following lines has been added to *.info file written by + dhcpcd: + INTERFACE= (e.g. INTERFACE=eth1) + CLASSID= (e.g. CLASSID="Linux 2.4.14 i686") + CLIENTID= (e.g. CLIENT_ID=10:32:C3:37:25:14 or + CLIENT_ID="test1") + 7. dhcpcd now will rename previous *.info file to *.info.old + + Other changes: + Tim Wright submitted patch to prevent dhcpcd + from altering network interface flags that it should not change. + Pavel Roskin submitted patch to dhcpcd.spec file + to fix the installation directories. + Tim Goodwin suggested using full-qualified + host names rather than truncating them at first ".". + +12/31/01 - v.1.3.21-pl2 + D. Hugh Redelmeier pointed out a problem with + binding udpFooSocket in client.c to address 0.0.0.0 port 68 and + exiting with error status if binding fails as in a case of more + than one dhcpcd process. This effectively prevented dhcpcd from + running on more than one interface. Fixed for now by disabling + error exit in a case udpFooSocket binding fails. Perhaps a better + solution is needed. + Thomas Aeby pointed out nisDomainName should not + be used in /etc/resolv.conf file. Fixed. + Roger Maclean suggested to increase + "time since bootup" parameter in DHCP message to 10, otherwise + dhcpcd may not get an IP address from WinNT DHCP server. + Jani Averbach suggested changes to Makefile.am to + make ./configure accept installation options. + Yaacov Akiba Slama submitted a patch to make use + dhcp-spoof feature of adsl modems/routers. The patch sets netmask to + 255.255.255.255 in a case the dhcpConfig routine fails to set it to + the netmask supplied by DHCP server. + +10/13/01 - v.1.3.21-pl1 + Pavel Roskin submitted patch for dhcpcd.spec.in + file to fix "rpm -ta dhcpcd-1.3.21-pl1.tar.gz" RPM package creation. + +10/09/01 - v.1.3.21-pl0 + Toralf Lund submitted patch to add + support for NIS and NTP server options in DHCP. -Y and -N + flags have been added to dhcpcd command line. Dhcpcd now creates + /etc/yp.conf and /etc/ntp.conf files unless -Y or -N + options are specified (see dhcpcd manual page). Among other things + in the patch: dhcpcd saves the hostname and domainname of the host + and restores it upon exit; dhcpcd now retries HWADDR_TRIES times + to retrieve NIC MAC address in dhcpStart(). + Jarno Huuskonen pointed out + dhcpcd sets mode of the pid file corresponding to the umask of + the calling process which may be a security risk if calling + process has umask 000 which happens when dhcpcd runs from APM + suspend/resume. Fixed by setting umask of dhcpcd process to 022 at + the very beginning in dhcpcd.c. + Olivier Baudron suggested using just one + dhcpcd.exe script, which is to run every time interface is + configured or brought down. The interface name will be passed as + first parameter and configuration state as second parameter to the + script. So /etc/dhcpc/dhcpcd.exe script is invoked as + /etc/dhcpc/dhcpcd.exe [ip_address] [-d] + Second parameter has value "up" when interface is brought up with + the same IP address as before, "new" when interface is brought up + with new IP address, and "down" when interface is brought down when + dhcpcd exits. This usage to the executable script was suggested by + Scott Gifford . +**** This version requires rewrite of dhcpcd*.exe script(s) as it is + incompatible with previous versions of dhcpcd. + +10/08/01 - v.1.3.20-pl2 + Fabrizio Gennari reported + dhcpcd could not add a static route supplied by his DHCP server. He suggested + changing a line in client.c + rtent.rt_flags = RTF_UP|RTF_HOST; + to + rtent.rt_flags = RTF_UP|RTF_HOST|RTF_GATEWAY; + which fixed the problem for him. I will give it a shot .. with RoadRunner + no matter how much you screw dhcpcd, it always works .. + Simon Oliver reported an interesting case + if DHCP server supplying dhcpAddrLeaseTime>0 and dhcpT1value=0 and + dhcpT2value=0 which made dhcpcd go mad about lease renewal. Fixed by + checking for dhcpT1value=0 and dhcpT2value=0 in client.c + +10/01/01 - v.1.3.20-pl1 + Matteo Frigo pointed out a bug in client.c: + in a case of class A network and DHCP server not supplying subnet mask + dhcpcd did not zero out second octet in subnet mask. + Elliot Lee submitted patches: + 1. dhcpcd to accept IEEE 802 TokenRing interface (not sure if this one + will actually make dhcpcd work with TokenRing, since + dhcpcd builds messages on top of Ethernet frames) + 2. make some globally defined variables to be local + 3. use nis domain name along with dns domain name in search string of + /etc/resolv.conf file. + 4. run a script when interface gets configured in addition to + /etc/dhcpc/dhcpcd-eth0.exe script which runs only when IP address + changes. S.V. - made the script name /etc/dhcpc/dhcpcd_up-eth0.exe + S.V - make dhcpcd run a script when interface goes down, the script is + /etc/dhcpc/dhcpcd_down-eth0.exe. This was also suggested by + Jason Bodnar + Craig Lawson pointed out to a bug + in dhcpcd when it runs on multiple interfaces. When dhcpcd exits + it tries to restore resolv.conf.sv back to resolv.conf even if + dhcpcd did not rename it at first. Fixed. + Olivier Baudron submitted patch to bind a + datagram socket to udp port 68 to prevent icmp error message from + the kernel. This problem has also been report by Robert Paluszak + . + S.V.- cleaned up "configure" scripts to make sure ./configure will + create the Makefile with correct installation paths. + +04/06/01 - v.1.3.20-pl0 + S.V - removed 0x0 from ClientID and ClassID options + +04/03/01 - v.1.3.19-pl9 + Young, Jeremy pointed out + to a bug introduced in v.1.3.19-pl6 which resulted in + 7-byte long MAC address with 0x0 at the end. Fixed. + +03/10/01 - v.1.3.19-pl8 + Rune Torgersen pointed out + at a bug introduced in v.1.3.19-pl7 with "rootPath" + option. The dhcpParamRequest had to be changed to 14. + The bug probably disabled "-h hostname" option to dhcpcd + in v.1.3.19-pl7. + +02/22/01 - v.1.3.19-pl7 + Chris Petro + submitted patch to disable processing of + "routersOnSubnet" DHCP option if it is not + provided by DHCP server, as "routersOnSubnet" is + indeed optional. + Jason A. Pattie + submitted patch to include "rootPath" DHCP option. + Peter Poeml submitted patch + to work around a problem with dhcpcd setting + hostname when it is not provided by DHCP server if + there is no initial /etc/resolv.conf file to + be able to resolv hostname from obtained IP address. + +01/14/01 - v.1.3.19-pl6 + Simon Byrnand reported the compilation + on older kernels broke again somewhere in pl3-pl5. + Pavel Roskin submitted patch to fix the + problem with compilation on older kernels. + S.V - added 0x0 to the end of ClientID and ClassID + options in the DHCP message. + +12/21/00 - v.1.3.19-pl5 + Pavel Roskin submitted patch: + README: + - Mention that MediaOne is now AT&T Broadband. dhcpcd works with it. + Makefile.am: + - Copy the binary dhcpcd to the distribution. Added a comment about + the dist-hook target. + configure.in: + - Remove AC_CANONICAL_TARGET - dhcpcd is not a compiler. + - Don't check Linux version - it can be determined at the compile time. + - Don't call uname directly - rely on the results of + AC_CANONICAL_HOST instead. + - Don't ever ignore predefined CFLAGS. + client.c: + - Include + - Define OLD_LINUX_VERSION for kernels older than 2.1.1. + + The patch is also available here: + http://www.red-bean.com/~proski/dhcpcd/dhcpcd-pl4.diff + +12/19/00 - v.1.3.19-pl4 + Pavel Roskin + submitted patch to work around broken version of automake + which was used in generating v.1.3.19-pl3. Also + dhcpcd-1.3.19-pl4.tar.gz has been generated using + "make distcheck" + +12/15/00 - v.1.3.19-pl3 + Nico Baggus + - added version checking to the cache file + - added support for specifying window size for the + gateway routes (default = 32768) (gives better throughput + when used for Cablenetworks...;-) + - modified defining the offsets in the ipudphdr & ipicmphdr + to get the stuff through gcc 2.96 + + Pavel Roskin + Makefile.am: + - Manuals and examples added to EXTRA_DIST + - dhcpcd.spec added to the distribution. + - dhcpcd.spec is now rebuilt by "make all". + - "make rpm" depends on "make distcheck" and uses the dhcpcd.conf + embedded into the tarball. + config.guess: + - Updated to the latest version. PA-Linux team will appreciate it. + config.sub: + - Likewise. + configure.in: + - Versioning simplified to ensure the right tarball name. + Removed dash from the patchlevel to accomodate rpm. + - Avoid square brackets or quote them properly. + dhcpcd.spec.in: + - Substitute "Source". + - "BuildRoot" should be under /var/tmp, not /usr/tmp. + - Don't use filelists - it breaks with rpm-3.0.5 that compresses + manuals. + - Include directory /etc/dhcpc. + - Exclude dhcpcd.spec.in from docs. + - Include any *.lsm file. + missing: + - Updated to avoid problems with future versions of automake. + +10/11/00 - v.1.3.19-pl2 + Nils Ohlmeier and + Warren Jones rightfully pointed out + nisDomainName should not be used in resolv.conf file. + Fixed. + +08/05/00 - v.1.3.19-pl1 + Simon Byrnand submitted patches to make + ioctl(dhcpSocket,SIOCSIFADDR,&ifr) call in dhcpStop() routine + applicable only to kernels versions > 2.0 and + to fix handling of SIGCHLD signal. + +08/05/00 - v.1.3.19-pl0 + Lenz Grimmer submitted patch to prevent + "unaligned memory access" warnings to appear on IA64-based systems. + +08/05/00 - v.1.3.18-pl9 + uncommented ioctl(dhcpSocket,SIOCSIFADDR,&ifr) call in dhcpStop() + routine to prevent interface from having invalid IP address + during DHCP negotiation. + + Simon Byrnand submitted patch to take + care of the following: + o Make dhcpcd both libc5 and glibc compatible + o Rebind dhcpSocket after change in IP address to avoid + problem with 2.0 kernel losing socket binding to the interface + after resetting of the interface + o Problem with lost DhcpRelease message under 2.0 kernel + when interface gets shut down + + Brian K. White submitted "Note 4." to the + README file. + +05/10/00 - v.1.3.18-pl8 + Konstantin Boldyshev submitted patch + to make dhcpcd work with 2.0 kernels. Modified configure script + to pass -DOLD_LINUX_VERSION flag to compiler if the kernel version + is 2.0.xx, in which case socket(AF_INET,SOCK_PACKET,..) call is used + instead of socket(AF_PACKET,SOCK_PACKET,..) and the local route + is added. Local route is added automatically under more recent kernels. + + Rolf Jentsch submitted patch to + add -T flag to the dhcpcd command line. With -T flag dhcpcd will + go through normal DHCP negotiation sequence but will not configure + the interface or otherwise change anything on the system. Useful for + testing DHCP servers. + +05/06/00 - v.1.3.18-pl7 + Simon Baatz submited patch to fix + possible problem in retransmitting DHCP requests, and make dhcpcd + adapt to possible change in DHCP server address in the middle of a + client's lease. + + Habibie submitted patch to include + GNU automake, autoconf, and RPM packaging features into dhcpcd + distribution. Now dhcpcd build follows usual GNU scheme: + + ./configure + make + + In any case, the old Makefile is also included. ./configure overwrites + it with generated version. + + Added "-n" flag to dhcpcd command line. Now "dhcpcd -n" will force + currently running dhcpcd to try to renew the lease. This behavior + is similar to "pump -R". + +04/15/00 - v.1.3.18-pl6 + Jarno Huuskonen submited patch to set + dhcpcd's process umask to 022 before creating /etc/resolv.conf file. + + Scott Bronson sent some feedback on how RH "pump" + behaves vs. dhcpcd. Now dhcpcd will also send second DHCP_DISCOVER + message. + + Performing checksum on received packets is now optional and can be + switched on with -C option on dhcpcd command line. + +03/27/00 - v.1.3.18-pl5 + Lenz Grimmer sent a patch to make dhcpcd do + reverse hostname lookup in a case DHCP server did not provide + hostName option with -H flag or in a case DHCP server did not provide + domainName option with -D flag to dhcpcd. + A bit enhanced version of the patch moved into "production". + +03/27/00 - v.1.3.18-pl4 + Removed "-m586" from Makefile. + The static executable contained with the distribution has been compiled + against glibc-2.1.3 and 2.3.99-pre3 kernel. + +10/27/99 - v.1.3.18-pl3 + Mike Hartman pointed out to include + NULL byte at the end of the HostName string. + +10/26/99 - v.1.3.18-pl2 + Mike Hartman submited a patch to fix + a bug in handling "-h" flag. Hostname option flag has been broken + since v.1.3.18-pl0. + +09/17/99 - v.1.3.18-pl1 + Put back "1.3.17-pl10" patch with some tweaking to get rid + of error in recvfrom call. Some minor cleanup. + +09/01/99 - v.1.3.18-pl0 + Reversed 1.3.17-pl10 patch. Binding dhcpSocket to the + interface produced error in recvfrom() call. + Chris G. Demetriou sent a patch + to make dhcpcd code portable to ARM platform. + Added "-s [ipaddr]" command-line option which makes dhcpcd + send DHCP_INFORM message. Added "-B" command-line option + to make dhcpcd solicit broadcast response. Added LOG_CONS option to + openlog(3). Changed "domain xxx" entry in resolv.conf to point + by default to nisDomainName, added "search nisDomainName" and + "search domainName" entries to resolv.conf file. + dhcpcd-.info file has minor changes to the format. + Namely, DNS and GATEWAY entries now will provide a comma-separated + list of corresponding IP addresses, not just the first IP address in + the list. Added support for static route option. + +07/23/99 - v.1.3.17-pl10. + Johan Verrept suggested "bind"-ing + dhcpSocket to the interface so the socket does not + receive packets from other interfaces. Change made to dhcpStart + routine to include a call to the bind(). + +07/09/99 - v.1.3.17-pl9. + PETAZZONI reported a case of + DHCP server responding with IpAddrLeaseTime=0 which + drove dhcpcd-1.3 mad. Added check for IpAddrLeaseTime=0 so + when dhcpcd receives IpAddrLeasetime=0 it will assume + DEFAULT_LEASETIME, infinite by default. + Added '-V' flag to dhcpcd syntax. Dhcpcd will print + copyright/version banner when used with '-V' flag. + +06/19/99 - v.1.3.17-pl8. + Olivier Baudron pointed out + to a problem with in_cksum routine when compiling with + egcs or gcc-2.8.xx compilers and proposed a patch to + work around the compiler bug. + Changed in_cksum routine in udpipgen.c file to + get rid of problems with wrong checksums if compiled + with egcs or gcc-2.8.xx compilers. + +06/10/99 - v.1.3.17-pl7. + Hans Andersson and some + other gentlemen pointed out at 64-bit uncleanless of + current dhcpcd code, and sent relevant patches. + This release is an attempt to make dhcpcd-1.3 + 64-bit safe. No new functionality has been added. + This is left for v.1.3.18. + +05/10/99 - v.1.3.17-pl6. + Andrew S. Howell submitted a patch + eliminating unnecessary padOptions in buildmsg.c file. + It helped with his cable modem. Removed + "Your IP address=xxx.xxx.xxx.xxx" message on a screen + when dhcpcd configures the interface. + +03/14/99 - v.1.3.17-pl5. + Mike Benoit submitted + debugging info. Change made to "client.c" to allow + dhcpcd to get router IP address from DHCP_ACK message + if it didn't come with DHCP_OFFER. + +03/10/99 - v.1.3.17-pl4. + Tim Auckland submitted + patch to dhcpcd-1.3.17-pl3 to close all standard + file descriptors when dhcpcd forks into background. + It should help with pcmcia cards which use popen() call. + +02/04/99 - v.1.3.17-pl3. + Sergei Viznyuk + Now if dhcpcd does not get DHCP_ACK for the same + IP address as before reboot, it will fall back + to dhcpInit and will send DHCP_DISCOVER message(s). + Dhcpcd will now write pid file before forking + into background not after. Updated manual page. + +01/15/99 - v.1.3.17-pl2. + Sergei Viznyuk + Changed the dhcpcd exec-bin directory from /usr/sbin to /sbin. + Pavel Polischouk sent a tcpdump + which inspired me to make some changes to the code + to avoid potential race condition when there are multiple + DHCP servers on the network. + +01/12/99 - v.1.3.17-pl1. + Marc ZYNGIER submitted another + patch to dhcpcd-1.3 to make it work on Linux Alpha + platforms. + +01/10/99 - v.1.3.17 + Sergei Viznyuk + Came across patch for dhcpcd-1.3.16 + submitted to linux.debian.alpha + by Marc Zyngier Marc.Zyngier@bull.net. + Changed the default lease time requested + to infinite. + Removed "mlip" client 'cause of www.ml.org death. + Did some other minor changes to the code. + +11/09/98 - v.1.3.16 + Sergei Viznyuk + Thanks to a great help from Brion Vibber + another nasty bug has been found and hopefully + squashed. Also the problem with setting default + route on some of the systems has been finally + solved. Kernel refuses to accept a route for a gateway + if its IP address does not seem to be on the same + subnet as in a case with bridged subnets. + The work around suggested by Brion Vibber is + to add a local route to the gateway. I hope we've got + it right in v.1.3.16. + +11/07/98 - v.1.3.15 + Sergei Viznyuk + Fixed rather nasty bug in dhcpSendAndRecv routine + introduced in v.1.3.13 which might have prevented + quite of few users from receiving DHCP_OFFER message. + Added command-line options -D,-H,-R to dhcpcd. + Request and patch submitted by Aron Griffis + +10/28/98 - v.1.3.14 + Sergei Viznyuk + Removed setting a local route in addition to default one + in v.1.3.13. This did not help with the problem + one user experiences with setting a default route but + rather resulted in duplicate entries for the local + route in the routing table. + +10/27/98 - v.1.3.13 + Sergei Viznyuk + Fixed a minor bug in dhcpSendAndRecv routine + which caused quite a few bogus "DHCP server declined request: op=XX" + messages in /var/log/debug file. + Add (or rather put back) setting of local route. + Normally the local route is set automatically by + the kernel when default route entry is added, however + as it seems that doesn't always work for everybody. + +10/25/98 - v.1.3.12 + Sergei Viznyuk + Made a good faith attempt to squash a bug in UDP/IP + layer of dhcpcd which might have been a cause of + problems on PPC-based systems. Originally reported + by Martin Costabel . + Rewrote quite a bit of UDP/IP code so if dhcpcd-1.3.12 + doesn't work for you at all you may try v.1.3.11. + There seemed to be a problem with setting default + route on 2.1.125 kernel reported by Brion Vibber + . Changed "dhcpConfig" to not force + dhcpcd to die if it cannot set default route. At least + it would be easier to find the cause of problem... + Also did some changes to "client.c" code to move it + closer to the point when one can add support for Token Ring + and/or other link protocols. + +10/15/98 - v.1.3.11 + Sergei Viznyuk + Put back '-c filename' option for dhcpcd due to + a requests from some users of Mediaone cable modems + who were trying to use 'ipup' et similar bootup scripts. + Originally requested by Robert Shapiro + Some minor fixes. + +10/13/98 - v.1.3.10 + Sergei Viznyuk + Added a new feature: whenever the assigned IP address for the + interface changes dhcpcd will execute /etc/dhcpc/dhcpcd-interface.exe + program. The word is substituted by + the actual interface name like e.g. eth0. + Caution: do not use /etc/dhcpc/dhcpcd-interface.exe as a bootup + script. It will not be executed if the assigned IP address + is the same as it was before reboot. + The included sample /etc/dhcpc/dhcpcd-interface.exe will log + the time of IP change to /var/log/messages file. + The included mlip program changes the IP address + for your host at DNS servers provided by www.ml.org + in a case you happen to be a member of Monolith's DynDNS. + Edit mlip.h file to supply your hostname, username, and password at + Monolith. Do "make mlip" to compile it. Then copy the executable + to /etc/dhcpc/dhcpcd-interface.exe. + + Added a compile time options '-DSETHOSTNAME' and '-DSETDOMAINNAME' + to Makefile. If used, dhcpcd will set hostname and/or domainname + of the host to the values it receives from DHCP server. + + Rehashed the Changes file to reverse the time order of entries. + +10/02/98 - v.1.3.9 + Sergei Viznyuk + Reduced the timeouts for sending and receiving DHCP messages. + Commented out arpCheck() call. It didn't work anyway + because there won't be ARP_REPLY message unless the + sender's IP address is set which defeats the purpose + of doing ARP check. This is something for the authors + of RFC 2131 to fix. + +09/04/98 - v.1.3.8 + Sergei Viznyuk + Some user reported he couldn't get dhcpcd to configure + interface because it failed to set broadcast address. + Changed the order dhcpcd configures the interface so it does + 1. sets IP address + 2. sets netmask + 3. sets broadcast address (redundant?) + Reduced the timeout for ARP check from 10secs to 3 secs, so + dhcpcd finishes faster. + +08/01/98 - + Sergei Viznyuk + Changed the "time since bootup" parameter in DHCP_DISCOVER + message from zero to 5 secs to accomodate for WinNT DHCP server + wishes. General cleanup. + +01/31/98 - + Sergei Viznyuk : + Changed dhcpcd to use socket(AF_PACKET,SOCK_PACKET,..) + instead of socket(AF_INET,SOCK_DGRAM,..) which did not + work with newer kernels. + Dropped 'dhcpcd -c filename' usage in favor of dhcpcd + returning valid exit status to the parent. + Added '-t timeout' option which specifies for how + long 'dhcpcd' will try to get an IP address before + forking into background. + Changed 'dhcpcd -d' option to be a debug flag. + + +======== before v.1.3 ============ + +08/28/97 1. added '-I' (client identifier) option. + 0.70 2. added '-h' (hostname) option (Note 10). + +04/24/97 changed the source UDP port from a random number to 68 + 0.65 because some servers respond to NOT port 68 but the source + UDP port in the received datagram (Note 9). + +03/16/97 1. fixed the bug that DHCPDECLINE message was RFC1541 + 0.6 compliant. Now dhcpcd can send both Interned Draft + compliant DHCPDECLINE message and RFC1541 compliant + one (mkDhcpDeclineMsg). + 2. fixed the bug that the broadcast address and the + subnetmask were set to the wrong value under the + following condition: + 1. dhcpcd is in the REBOOTING state + 2. received DHCP ACK msg does not include the + broadcast or subnetmask option. + (rebooting in client.c) + 3. fixed the bug that dhcpcd does not send a DHCPDECLINE + msg when it detects the duplicate IP adddress + (arpCheck in arp.c).. + 4. changed the way to make a DHCPREQUEST msg in the + SELECTING state (selecting, mkDhcpRequestMsg) + 5. changed the pcmcia/network script to unmount the NFS + filesystems before invoking "dhcpcd -k" command when + the card service goes down. + 6. added a new environment variable DHCP_DEVICE, which + contains the name of network interface to which + dhcpcd is attached. + +03/07/97 1. fixed the bug that the renewal time and the rebind time + are messed up (becomes minus number :p) when dhcpcd gets + the lease time whose least significant byte is greater + than or equal to 0x80 (setDhcpInfo in client.c) (Note 7). + For example, if the lease time is 24 hours, dhcpcd does + not work. + 2. added the hostname option to the parameter request list + (mkDhcpDiscoverMsg and mkDhcpRequestMsg in client.c) + 3. fixed the bug that dhcpcd sends a DHCPREQUEST message + which does not have the server identifier option in the + SELECTING state (mkDhcpRequestMsg in client.c) + 4. fixed the bug that dhcpcd uses the information from the + DHCPOFFER message for configuring the host (it must use + the information from the DHCPREQUEST message) (initHost + in client.c) (Note 8). + +01/30/97 made version 0.5a2 into 0.5, and released it. + 0.5 + +01/20/97 changed init, renewing, rebinding (client.c), and + 0.5a2 rcvAndCheckDhcpMsg (socket-if.c) to fix the bug that dhcpcd + exited with holding the assigned IP address when it failed in + invoking sendto system call in the RENEWING state. This happened + when the server is down in the RENEWING state. It causes + hosts to use expired IP addresses (how dangerous!). Now + dhcpcd does not exit even when it gets an error from sendto + in the RENEWING state. It continues to use the assigned IP + address until the lease time is expired, then it + initializes the network interface and goes into the INIT + state (Note 6). + +01/13/97 1. added IFF_MULTICAST in initHost (client.c) (Note 1). + 0.5a 2. fixed the bug that dhcpcd core-dumped when it received a + datagram containig the DHCP message option (parseDhcpMsg + in options.c) (Note 2). + 3. added -r option which makes dhcpcd RFC1541 compliant + (Note 3). + 4. changed mkDhcpRequestMsg (client.c) to put the + parameter request list option into the DHCPREQUEST + message in order to support the CMU version of DHCP + server (Note 4). But I do not check whether it works + with the CMU version of DHCP server. + 5. changed the argument to logOpen from LOG_CONS to LOG_PID + (Note 5). + 6. add nextState initialization in rebinding (client.c). + 7. changed the host information file name from "hostinfo" + to "hostinfo-ifname" (saveHostInfo in hostinfo.c) + (Note 5). Ifname is actually replaced with the network + interface name like "eth0". This is good when multiple + dhcpcd's attach to different network interfaces. + +09/22/96 made dhcpcd compliant to the Internet Draft in order to + 0.4 work with ISC version of DHCP server. + Changed client.c, options.c, socket-if.c + +09/19/96 quick fix to make it work with ISC's dhcpd. I made BROACAST + 0.33 flag available and added the NEED_BCAST_RESPONSE macro. + ISC's DHCP server is the Internet Draft compliant, but + dhcpcd is RFC1541 compliant. So this is a "workaround" version. + +09/17/96 added the code checking option field to parseDhcpMsg (options.c) + 0.32 + +09/16/96 fixed a typo in selecting (client.c) + 0.31 + +09/13/96 1. enhanced NTP support. Now dhcpcd creates the file, ntp.conf + 0.3 in the directory, /etc/dhcpc. + 2. added the code verifying if router addresses are correct + +09/12/96 added the following sample shell scripts: + 0.3b 1. "network" for pcmcia-cs + 2. "rc" scripts (rc.inet1, rc.inet2, rc.M) + 3. "rc.dhcp", a command file which can be executed from dhcpcd + +09/11/96 1. fixed a bug in setDefRoute (if.c). rt_flags was RT_UP. + 0.3a It should be RT_GATEWAY. + 2. fixed typos in openRecvSocket (socket-if.c) + 3. changed the way to invoke a command file from using + signal to forking twice + 4. removed unnecessary socket close/re-open + +09/09/96 added support to the "router" option. + 0.25a changed files: options.c, dhcp-options.h, dhcp.h, hostinfo.c, + if.c, client.c + +08/09/96 added the code to make a copy of the DHCP options in the + 0.2 DHCPOFFER message because Windows NT server does not put + DHCP options in the DHCPACK message except for netmask, T1 + time, and T2time. Other DHCP options are only in the + DHCPOFFER message. + +07/27/96 added '-i' option specifying the class identifier because + 0.2a RFC1541 says "The client implementation of DHCP should + provide a mechanism for the user to select directly the + 'class-identifier' value.". + +07/23/96 1. moved ARP check from just after dhcpcd received a + 0.2a DHCPOFFER message to just after dhcpcd received a + DHCPACK message. + 2. added 'Parameter Request List' in the DHCPDISCOVER message. + 3. added code to output the content of DHCP message option from + the server + +Note 1: Koji Okamura suggested this. +Note 2: This fix was made by Dan Halbert. +Note 3: Dan Halbert found that dhcpcd-0.4 does not work with some + RFC1541 compliant DHCP servers, and made a patch for it. + Brandon Mitchell suggested -r option. +Note 4: N. Komazaki found that CMU's DHCP server (dhcpd-3.3.7 + +patch) requires the parameter request option in the + DHCPREQUEST message. +Note 5: Ulrich Windl suggested this. +Note 6: Koji Okamura found this bug. +Note 7: Andrew Kieschnick found this bug. +Note 8: Tim Riker found this bug. +Note 9: I found this problem by using the tcpdump log which + Larry Hawkins sent me. +Note 10: I found some DHCP servers require this option by using the + tcpdump log which David Filiatrault sent me. + diff --git a/dhcpcd/Makefile.am b/dhcpcd/Makefile.am new file mode 100644 index 0000000000..2bc2a17cc2 --- /dev/null +++ b/dhcpcd/Makefile.am @@ -0,0 +1,24 @@ +INCLUDES = -I${top_srcdir} -I${top_srcdir}/src + +AM_CPPFLAGS = \ + $(NM_CFLAGS) \ + -DBINDIR=\"$(bindir)\" \ + -DDATADIR=\"$(datadir)\" + +noinst_LIBRARIES = libdhcpc.a + +libdhcpc_a_SOURCES= \ + udpipgen.c \ + udpipgen.h \ + buildmsg.c \ + buildmsg.h \ + arp.c \ + arp.h \ + client.c \ + client.h \ + dhcpcd.c \ + dhcpcd.h + +bin_PROGRAMS = dhcp_test +dhcp_test_SOURCES = dhcp_test.c +dhcp_test_LDADD = libdhcpc.a diff --git a/dhcpcd/NEWS b/dhcpcd/NEWS new file mode 100644 index 0000000000..9829f28b8a --- /dev/null +++ b/dhcpcd/NEWS @@ -0,0 +1,3 @@ +Please refer to +http://www.phystech.com/download/ + diff --git a/dhcpcd/README b/dhcpcd/README new file mode 100644 index 0000000000..225dc8ea68 --- /dev/null +++ b/dhcpcd/README @@ -0,0 +1,276 @@ +0. Introduction + +This is an RFC2131,RFC2132, and RFC1541 compliant DHCP client daemon. +RFC1541 was obsoleted by RFC2131, but there are still some RFC1541 compliant +DHCP servers. dhcpcd gets an IP address and other information from a +corresponding DHCP server, configures the network interface +automatically, and tries to renew the lease time according to RFC2131 +or RFC1541 depending on the command line option. + +dhcpcd-1.3 has been reported to compile +on Intel,PPC, and Alpha-based Linux platforms +providing glibc-2.0.5 or later has been +installed. Please refer to the Notes below for details. + +dhcpcd-1.3 has been reported as compatible with DHCP servers +used by the following network service providers: + +1. Time Warner RoadRunner http://www.rr.com/ +2. MediaOne (now AT&T Broadband) http://www.attbroadband.com/ +3. Comcast.Net, formerly @Home Networks http://www.comcast.net/ +4. France Telecom ADSL http://www.wanadoo.fr/ +5. USWest.net DSL (now Qwest) http://www.uswest.com/ +6. France CyberCable http://www.cybercable.fr/ +7. BellSouth ADSL http://www.bellsouth.net/ +8. BCtel Multimedia Gateway ADSL http://www.bctel.net/ +9. Cogeco Cable Canada http://www.cogeco.ca/ +10.Sympatico High Speed Edition ADSL http://www.hse.sympatico.ca/ +11.Adelphia PowerLink http://powerlink.adelphia.net/ +12.Videotron, Canada http://www.videotron.ca/ +13.Access Cable, Nova Scotia, Canada http://www.accesscable.net/ +14.A2000 Cable, Netherlands http://www.a2000.nl/ +15.Tele-Communications, Inc http://www.tci.com/ +16.Telenet, Belgium http://www.telenet.be/ +17.Telekabel Wien, Austria http://www.telekabel.at/ +18.RMCnet, France http://www.rmcnet.fr/ +19.Retecal, Spain http://www.retecal.es/ +20.TVD, Belgium http://www.tvd.net/ +21.Optimum Online, NY http://www.optimumonline.com/ +22.Knology Comm. http://www.knology.com/ +23.Highpernet, Switzeland. http://www.highpernet.ch/ +24.TeledisNet, Belgium. http://www.teledisnet.be/ +25.Southwestern Bell DSL. http://www.swbell.net/ +26.Brutele, Belgium. http://www.brutele.be/ +27.Telus, Canada. http://www.telusplanet.net/ +28.Chello, Netherlands. http://www.chello.nl/ +29.RCN. http://www.rcn.com/ +30.Pandora, Belgium. http://www.pandora.be/ +31.Armstrong's Cable Services, PA. http://www.zbzoom.net/ +32.21st Century, Chicago. http://www.21stcentury.net/ +33.Supercable, Spain. http://www.supercable.es/ +34.Primacom, Germany. http://www.primacom.net/ +35.Click! Network, Tacoma, WA. http://www.click-network.com/ +36.Telocity, Cupertino, CA. http://www.telocity.com/ +37.Charter Communications. http://www.chartercom.com/ +38.Tebenet, Netherlands. http://www.tebenet.nl/ +39.ZoomTown, Cincinnati, OH. http://www.zoomtown.com/ +40.Telecom New Zealand Jetstream ADSL. http://www.telecom.co.nz/ +41.Belgacom Turboline ADSL. http://www.turboline.be/ +42.ISP Channel. http://www.ispchannel.com/ +43.Telia.Com Sweden. http://www.telia.com/ +44.Netcabo Portugal. http://www.netcabo.pt/ +45.CyberCity xDSL, Denmark. http://www.cybercity.dk/ +46.Tokyo Metallic Comm. http://www.metallic.co.jp/ +47.Telenor, Norway. http://www.telenor.no/ +48.Telstra, Austria. http://www.telstra.com/ +49.Look Wireless, Montreal. http://www.look.ca/ +50.Virtua, Brazil. http://www.virtua.com.br/ +51.Verizon DSL. http://www.verizon.com/dsl/ +52.Sonera, Netherlands. http://www.soneraplaza.nl/ +53.NTL, UK. http://www.ntl.co.uk/cablemodems/ +54.Telewest, UK. http://www.telewest.co.uk/ +55.VTR, Chile. http://www.vtr.net/ +56.Millennium Digital Media. http://www.mdm.net/ +57.Madritel, Spain. http://www.madritel.es/ +58.Cistron Telecom, Netherlands. http://www.cistron.nl/ +59.Cox Express, Las Vegas. http://www.cox.com/ +60.Cablecom GMBH, Switzerland. http://www.hispeed.ch/ +61.Elektro Ablasser Hausmannstaetten, Austria. http://www.catv4u.at/ +62.Kiva Networking, Indiana. http://www.kiva.net/ +63.Blueyonder, UK. http://www.blueyonder.co.uk/ +64.Salzburg-Online, Austria. http://www.salzburg-online.at/ +65.Cablenet, Colombia. http://www.cable.net.co/ +66.i-Cable, Hong Kong. http://www.i-cable.com/ +67.Shaw High Speed. http://www.shaw.ca/ +68.Rogers Communications. http://www.rogers.com/ +69.Chello, France. http://www.chello.fr/ +70.Acesserapido, Brazil. http://www.acesserapido.com.br/ +71.Wirefire. http://www.wirefire.com/ +72.Ajato, Brazil. http://www.ajato.com.br/ +73.TDC/TeleDanmark, Denmark. http://www.teledanmark.dk/ +74.Telstra Bigpond Broadband ADSL, Australia. http://www.bigpond.com.au/ +75.Eastern Connecticut Cable. http://www.myeastern.com/ +76.ADSL Brazil Telecom. http://www.internetturbo.com.br/ +77.InsightBB.com. http://www.insightbb.com/ +78.S?derhamn Teknikpark AB, Sweden. http://www.teknikpark.se/ +79.Tele 2, Sweden. http://www.tele2.se/ + +if you have been successfully using dhcpcd-1.3 +on your network please report the fact along +with network provider's name/URL/whatever and dhcpcd version +to the author . + +dhcpcd-1.3 primary web site is +http://www.phystech.com/download/ +ftp://ftp.phystech.com/pub/ + +1. Install + +Make sure your kernel is compiled with support for SOCK_PACKET +(CONFIG_PACKET option). Cd to source distribution directory. Do +./configure --prefix=/ +Please note the GNU default installation --prefix=/usr/local +is not what most users want for dhcpcd installation. +Edit Makefile to customize compile time options. +Do 'make' followed by 'make install'. +To enable dhcpcd error logging add the following line to your +/etc/syslog.conf file: +local0.* /var/log/dhcpcd.log +and then refresh syslogd daemon: +kill -1 `cat /var/run/syslogd.pid` + + Note 1. + to compile dhcpcd-1.3.X you have to install glibc-2.0.5 or later. + dhcpcd-1.3.X might not compile under libc.5. + If you don't have glibc installed you can use the precompiled + binary included with the distribution. + If you are trying to compile dhcpcd yourself and getting error + "cannot find net/ethernet.h file", you don't have glibc + installed. + + Note 2. + some releases of GNU C compiler, notably + gcc-2.8.1 are buggy. The same goes for egcs as of 05/10/99. + If you have compiled dhcpcd with gcc-2.8.1 or egcs you may + get the following errors in dhcpcd.log file: + May 4 12:43:03 dhcpcd[423]: corrupted UDP msg with uh_ulen=319 in_cksum=-2 discarded + and dhcpcd won't work. The workaround is to compile dhcpcd without + -O2 in Makefile. + + Note 3. + if you are trying to run dhcpcd and are getting the following error in + the log file: + dhcpcd[xx]: dhcpStart: socket(): Invalid argument + it means you kernel is compiled without support for SOCK_PACKET + (CONFIG_PACKET option). + + Note 4. + if your dhcpcd binary compiles fine and runs OK with "--help" flag + only and otherwise immediately coredumps with "Segmentation Fault" + error then delete /etc/dhcpc/dhcpcd-.cache file and + try running dhcpcd again. There is a chance your dhcpcd cache file + is from old version of dhcpcd. + + Note 5. + If you replace your network card or upgrade to a different version of + dhcpcd you might not be able to obtain the same old IP address from + DHCP server. This is because the DHCP server identifies clients by + ClientID DHCP option which by default is MAC address of the network + card. The work around is to use -I ClientID option with some + unique "ClientID" string. + Also, upgrading to a different version of dhcpcd invalidates *.cache + file where dhcpcd stores IP address which it tries to renew on restart. + +2. How to Use It + +Invoke the client by typing 'dhcpcd'. Note you should NOT +explicitly put it in the background with the '&' character - +background processing is automatic unless 'dhcpcd' was +compiled with -DDEBUG flag. Dhcpcd will fork into background +as soon as it configures the interface. By default, dhcpcd will +attach to 'eth0' unless you explicitly give an interface name on the +command line. +The example below demonstrates dhcpcd usage in a case where +linux box serves as a router/firewall for the local network 192.168.12.0. + +if dhcpcd eth1; then + inetd + /usr/sbin/sendmail -bd + httpd + echo 1 > /proc/sys/net/ipv4/ip_forward + modprobe ip_tables + modprobe iptable_nat + modprobe iptable_filter + modprobe ipt_MASQUERADE + modprobe ip_nat_ftp + modprobe ip_conntrack_ftp + iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE +else + echo "**** Unable to configure eth0" +fi + +The bootup process will wait until 'dhcpcd' configures +interface or until dhcpcd times out before proceeding further. + +Any time dhcpcd configures or shuts down interface it will try to +execute /dhcpcd.exe script with appropriate +parameters passed. The exact pathname of the executable script can be +changed with "-c ExecFilePath" dhcpcd option. The +directory can be specified with "-L " option, otherwise +it defaults to /etc/dhcpc/. The dhcpcd.exe script invokation is: +/dhcpcd.exe [-d] +where is actually /dhcpcd-.info +file; optional parameter [-d] is a debug flag passed if dhcpcd has +been invoked with -d flag. The second parameter to dhcpcd.exe script is +"up" if the interface has been configured with the same IP +address as before reboot, "down" if the interface has been shut +down, "new" if the interface has been configured with new IP address. + +3. Supported DHCP Options + +The current version of dhcpcd supports the following DHCP options: + + o lease time + o renewal (T1) time + o rebind (T2) time + o netmask + o broadcast address + o router + o dns + o host name + o domain name + o nis domain name + o nis servers + o ntp servers + o static routes + +5. Cache File + +dhcpcd saves the assigned IP address into the file +/dhcpcd-.cache (the word is actually +replaced with the interface name like eth0, etc. to which dhcpcd is +attached) so that it can try to use that IP address when it is invoked +next time. Remove the file /dhcpcd-.cache before +you invoke dhcpcd unless you like using the previously assigned IP +address. + +6. Information File + +dhcpcd writes the configuration information into +/dhcpcd-.info file. The word is actually +replaced with the interface name like eth0, etc. to which dhcpcd is +attached. That file may be included into a Bourne or Korn shell script +to set an environment variables like e.g. HOSTNAME, DOMAIN, NETMASK, etc. +The supplied sample /dhcpcd.exe script demonstrates usage +of /dhcpcd-.info file. + +7. Other Information + +dhcpcd sends DHCP_RELEASE message to the DHCP server, deletes the +/dhcpcd-.cache file and brings the attached +network interface down when it gets SIGHUP signal. It will +not send DHCP_RELEASE message and will not delete +/dhcpcd-.cache file in a case it gets +SIGTERM as normally happens upon reboot. + +dhcpcd may be used to obtain multiple IP addresses for the same +dummy interface providing one invokes dhcpcd with +-I ClientID -L ConfigDir -T -c ExecFilePath +options where ClientID and ConfigDir are unique to each of the requested +IP addresses. The same way it can be used to obtain IP addresses +for virtual interfaces, e.g. eth0:1 + +dhcpcd currently supports only Ethernet link protocol. + +8. In case dhcpcd does not work: + Run 'dhcpcd -d' and mail me the relevant messages + from /var/log/dhcpcd.log file. Also run + tcpdump -evvn -i eth0 + and mail me the results of that. + If the things are too bad for you, + uncomment -DDEBUG flag in Makefile + and recompile 'dhcpcd'. Run 'dhcpcd -d' + and mail me what you see. + +Sergei Viznyuk + diff --git a/dhcpcd/arp.c b/dhcpcd/arp.c new file mode 100644 index 0000000000..f33e0ddc87 --- /dev/null +++ b/dhcpcd/arp.c @@ -0,0 +1,229 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 +#include +#include +#include +#include +#include "client.h" +#include "arp.h" + +typedef struct arpMessage +{ + struct packed_ether_header ethhdr; + u_short htype; /* hardware type (must be ARPHRD_ETHER) */ + u_short ptype; /* protocol type (must be ETHERTYPE_IP) */ + u_char hlen; /* hardware address length (must be 6) */ + u_char plen; /* protocol address length (must be 4) */ + u_short operation; /* ARP opcode */ + u_char sHaddr[ETH_ALEN]; /* sender's hardware address */ + u_char sInaddr[4]; /* sender's IP address */ + u_char tHaddr[ETH_ALEN]; /* target's hardware address */ + u_char tInaddr[4]; /* target's IP address */ + u_char pad[18]; /* pad for min. Ethernet payload (60 bytes) */ +} __attribute__((packed)) arpMessage; + +#define BasicArpLen(A) (sizeof(A) - (sizeof(A.ethhdr) + sizeof(A.pad))) + +extern int DebugFlag; + +int eth2tr(struct packed_ether_header *frame, int datalen); +int tr2eth(struct packed_ether_header *frame); + +/*****************************************************************************/ +#ifdef ARPCHECK +int arpCheck(const dhcp_interface *iface) +{ + arpMessage arp_msg_send; + arpMessage arp_msg_recv; + struct sockaddr addr; + int j,i=0,len=0; + + memset (&arp_msg_send, 0, sizeof(arpMessage)); + memcpy (arp_msg_send.ethhdr.ether_dhost, MAC_BCAST_ADDR, ETH_ALEN); + memcpy (arp_msg_send.ethhdr.ether_shost, iface->chaddr, ETH_ALEN); + arp_msg_send.ethhdr.ether_type = htons(ETHERTYPE_ARP); + + arp_msg_send.htype = (iface->bTokenRing) ? htons(ARPHRD_IEEE802_TR) : htons(ARPHRD_ETHER); + arp_msg_send.ptype = htons(ETHERTYPE_IP); + arp_msg_send.hlen = ETH_ALEN; + arp_msg_send.plen = 4; + arp_msg_send.operation = htons(ARPOP_REQUEST); + memcpy (arp_msg_send.sHaddr, iface->chaddr, ETH_ALEN); + memcpy (&arp_msg_send.tInaddr, &(iface->ciaddr), 4); + + if ( DebugFlag ) + { + syslog(LOG_DEBUG, "broadcasting ARPOP_REQUEST for %u.%u.%u.%u\n", + arp_msg_send.tInaddr[0],arp_msg_send.tInaddr[1], + arp_msg_send.tInaddr[2],arp_msg_send.tInaddr[3]); + } + + do + { + do + { + if ( i++ > 4 ) + return 0; /* 5 probes */ + memset (&addr, 0, sizeof(struct sockaddr)); + memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); + if ( iface->bTokenRing ) + len = eth2tr (&arp_msg_send.ethhdr, BasicArpLen(ArpMsgSend)); + else + len = sizeof (arpMessage); + if ( sendto(iface->sk, &arp_msg_send, len, 0, &addr, sizeof(struct sockaddr)) == -1 ) + { + syslog(LOG_ERR,"arpCheck: sendto: %m\n"); + return -1; + } + } while ( peekfd(iface->sk,50000) ); /* 50 msec timeout */ + + do + { + memset (&arp_msg_recv, 0, sizeof(arpMessage)); + j = sizeof(struct sockaddr); + if ( recvfrom(iface->sk, &arp_msg_recv, sizeof(arpMessage), 0, (struct sockaddr *)&addr, &j) == -1 ) + { + syslog(LOG_ERR,"arpCheck: recvfrom: %m\n"); + return -1; + } + if ( iface->bTokenRing ) + { + if ( tr2eth (&arp_msg_recv.ethhdr) ) + continue; + } + + if ( arp_msg_recv.ethhdr.ether_type != htons(ETHERTYPE_ARP) ) + continue; + if ( arp_msg_recv.operation == htons(ARPOP_REPLY) ) + { + if ( DebugFlag ) + syslog(LOG_DEBUG, "ARPOP_REPLY received from %u.%u.%u.%u for %u.%u.%u.%u\n", + arp_msg_recv.sInaddr[0],arp_msg_recv.sInaddr[1], + arp_msg_recv.sInaddr[2],arp_msg_recv.sInaddr[3], + arp_msg_recv.tInaddr[0],arp_msg_recv.tInaddr[1], + arp_msg_recv.tInaddr[2],arp_msg_recv.tInaddr[3]); + } + else + continue; + if ( memcmp (arp_msg_recv.tHaddr, iface->chaddr, ETH_ALEN) ) + { + if ( DebugFlag ) + syslog(LOG_DEBUG, + "target hardware address mismatch: %02X.%02X.%02X.%02X.%02X.%02X received, %02X.%02X.%02X.%02X.%02X.%02X expected\n", + arp_msg_recv.tHaddr[0],arp_msg_recv.tHaddr[1],arp_msg_recv.tHaddr[2], + arp_msg_recv.tHaddr[3],arp_msg_recv.tHaddr[4],arp_msg_recv.tHaddr[5], + iface->chaddr[0],iface->chaddr[1], + iface->chaddr[2],iface->chaddr[3], + iface->chaddr[4],iface->chaddr[5]); + continue; + } + if (memcmp (&arp_msg_recv.sInaddr, &(iface->ciaddr), 4)) + { + if ( DebugFlag ) + syslog(LOG_DEBUG, "sender IP address mismatch: %u.%u.%u.%u received, %u.%u.%u.%u expected\n", + arp_msg_recv.sInaddr[0],arp_msg_recv.sInaddr[1],arp_msg_recv.sInaddr[2],arp_msg_recv.sInaddr[3], + ((unsigned char *)&(iface->ciaddr))[0], + ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], + ((unsigned char *)&(iface->ciaddr))[3]); + continue; + } + return 1; + } while ( peekfd(iface->sk,50000) == 0 ); + } while ( 1 ); + + return 0; +} +#endif +/*****************************************************************************/ +int arpRelease(const dhcp_interface *iface) /* sends UNARP message, cf. RFC1868 */ +{ + arpMessage ArpMsgSend; + struct sockaddr addr; + int len; + const int inaddr_broadcast = INADDR_BROADCAST; + + /* build Ethernet header */ + memset (&ArpMsgSend,0,sizeof(arpMessage)); + memcpy (ArpMsgSend.ethhdr.ether_dhost, MAC_BCAST_ADDR, ETH_ALEN); + memcpy (ArpMsgSend.ethhdr.ether_shost, iface->chaddr, ETH_ALEN); + ArpMsgSend.ethhdr.ether_type = htons(ETHERTYPE_ARP); + + /* build UNARP message */ + ArpMsgSend.htype = (iface->bTokenRing) ? htons(ARPHRD_IEEE802_TR) : htons(ARPHRD_ETHER); + ArpMsgSend.ptype = htons(ETHERTYPE_IP); + ArpMsgSend.plen = 4; + ArpMsgSend.operation= htons(ARPOP_REPLY); + memcpy (&ArpMsgSend.sInaddr, &(iface->ciaddr), 4); + memcpy (&ArpMsgSend.tInaddr, &inaddr_broadcast, 4); + + memset(&addr,0,sizeof(struct sockaddr)); + memcpy(addr.sa_data,iface->iface,strlen (iface->iface)); + if ( iface->bTokenRing ) + len = eth2tr (&ArpMsgSend.ethhdr, BasicArpLen(ArpMsgSend)); + else + len = sizeof (arpMessage); + if ( sendto (iface->sk, &ArpMsgSend, len, 0, &addr, sizeof(struct sockaddr)) == -1 ) + { + syslog (LOG_ERR,"arpRelease: sendto: %m\n"); + return -1; + } + return 0; +} +/*****************************************************************************/ +int arpInform(const dhcp_interface *iface) +{ + arpMessage ArpMsgSend; + struct sockaddr addr; + int len; + const int inaddr_broadcast = INADDR_BROADCAST; + + memset (&ArpMsgSend, 0, sizeof(arpMessage)); + memcpy (ArpMsgSend.ethhdr.ether_dhost, MAC_BCAST_ADDR, ETH_ALEN); + memcpy (ArpMsgSend.ethhdr.ether_shost, iface->chaddr, ETH_ALEN); + ArpMsgSend.ethhdr.ether_type = htons(ETHERTYPE_ARP); + + ArpMsgSend.htype = (iface->bTokenRing) ? htons(ARPHRD_IEEE802_TR) : htons(ARPHRD_ETHER); + ArpMsgSend.ptype = htons(ETHERTYPE_IP); + ArpMsgSend.hlen = ETH_ALEN; + ArpMsgSend.plen = 4; + ArpMsgSend.operation= htons(ARPOP_REPLY); + memcpy (ArpMsgSend.sHaddr, iface->chaddr, ETH_ALEN); + memcpy (ArpMsgSend.tHaddr, iface->shaddr, ETH_ALEN); + memcpy (ArpMsgSend.sInaddr, &(iface->ciaddr), 4); + memcpy (ArpMsgSend.tInaddr, &inaddr_broadcast, 4); + + memset (&addr, 0, sizeof(struct sockaddr)); + memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); + if ( iface->bTokenRing ) + len = eth2tr(&ArpMsgSend.ethhdr,BasicArpLen(ArpMsgSend)); + else + len = sizeof(arpMessage); + if ( sendto(iface->sk,&ArpMsgSend,len,0, &addr,sizeof(struct sockaddr)) == -1 ) + { + syslog(LOG_ERR,"arpInform: sendto: %m\n"); + return -1; + } + return 0; +} diff --git a/dhcpcd/arp.h b/dhcpcd/arp.h new file mode 100644 index 0000000000..9f6758324f --- /dev/null +++ b/dhcpcd/arp.h @@ -0,0 +1,32 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 ARP_H +#define ARP_H + +#ifdef ARPCHECK +int arpCheck(const dhcp_interface *iface); +#endif +int arpRelease(const dhcp_interface *iface); +int arpInform(const dhcp_interface *iface); + +#endif diff --git a/dhcpcd/buildmsg.c b/dhcpcd/buildmsg.c new file mode 100644 index 0000000000..1ebdb1050f --- /dev/null +++ b/dhcpcd/buildmsg.c @@ -0,0 +1,329 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 Softwarme + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include "client.h" +#include "buildmsg.h" +#include "udpipgen.h" + +#include + +extern int DebugFlag; + +/*****************************************************************************/ +void fill_common_fields (dhcp_interface *iface, udpipMessage *msg, unsigned char dhost_addr[6], int bcast_rep) +{ + dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); + int magic_cookie = htonl (MAGIC_COOKIE); + + /* build Ethernet header */ + memcpy (msg->ethhdr.ether_dhost, dhost_addr, ETH_ALEN); + memcpy (msg->ethhdr.ether_shost, iface->chaddr, ETH_ALEN); + msg->ethhdr.ether_type = htons (ETHERTYPE_IP); + + dhcp_msg->op = DHCP_BOOTREQUEST; + dhcp_msg->htype = (iface->bTokenRing) ? ARPHRD_IEEE802_TR : ARPHRD_ETHER; + dhcp_msg->hlen = ETH_ALEN; + dhcp_msg->xid = iface->xid; + dhcp_msg->secs = htons(10); + + if ( bcast_rep && iface->client_options->do_broadcast_response ) + dhcp_msg->flags = htons (BROADCAST_FLAG); + + memcpy (dhcp_msg->chaddr, iface->chaddr, ETH_ALEN); + memcpy (dhcp_msg->options, &magic_cookie, 4); +} + +/*****************************************************************************/ +unsigned char *fill_host_and_class_id (dhcp_interface *iface, unsigned char *p) +{ + const char *host_name = iface->client_options->host_name; + int host_name_len = strlen (host_name); + + if ( host_name_len ) + { + *p++ = hostName; + *p++ = host_name_len; + memcpy (p, host_name, host_name_len); + p += host_name_len; + } + *p++ = dhcpClassIdentifier; + *p++ = iface->cls_id_len; + memcpy (p, iface->cls_id, iface->cls_id_len); + p += iface->cls_id_len; + memcpy (p, iface->cli_id, iface->cli_id_len); + p += iface->cli_id_len; + + return p; +} + +/*****************************************************************************/ +unsigned char *fill_param_request (unsigned char *p) +{ + *p++ = dhcpParamRequest; + *p++ = 14; + *p++ = subnetMask; + *p++ = routersOnSubnet; + *p++ = dns; + *p++ = hostName; + *p++ = domainName; + *p++ = rootPath; + *p++ = defaultIPTTL; + *p++ = broadcastAddr; + *p++ = performMaskDiscovery; + *p++ = performRouterDiscovery; + *p++ = staticRoute; + *p++ = nisDomainName; + *p++ = nisServers; + *p++ = ntpServers; + return p; +} + +/*****************************************************************************/ +unsigned char *fill_requested_ipaddr (dhcp_interface *iface, unsigned char *p) +{ + *p++ = dhcpRequestedIPaddr; + *p++ = 4; + memcpy (p, &(iface->ciaddr), 4); + p += 4; + return p; +} + +/*****************************************************************************/ +unsigned char *fill_lease_time (unsigned int *lease_time, unsigned char *p) +{ + *p++ = dhcpIPaddrLeaseTime; + *p++ = 4; + memcpy (p, lease_time, 4); + p += 4; + return p; +} + +/*****************************************************************************/ +unsigned char *fill_server_id (unsigned int *server_id, unsigned char *p) +{ + *p++ = dhcpServerIdentifier; + *p++ = 4; + memcpy (p, server_id, 4); + p += 4; + return p; +} + +/*****************************************************************************/ +unsigned char *fill_message_type (unsigned char request, unsigned char *p) +{ + const unsigned short dhcpMsgSize = htons(sizeof(dhcpMessage)); + + *p++ = dhcpMessageType; + *p++ = 1; + *p++ = request; + *p++ = dhcpMaxMsgSize; + *p++ = 2; + memcpy (p, &dhcpMsgSize, 2); + p += 2; + return p; +} + +/*****************************************************************************/ +udpipMessage *buildDhcpDiscover(dhcp_interface *iface) +{ + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + register unsigned char *p = dhcp_msg->options + 4; + unsigned int lease_time = htonl (iface->default_lease_time); + + fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); + p = fill_message_type (DHCP_DISCOVER, p); + if ( iface->ciaddr ) + { + if ( iface->client_options->do_rfc1541 ) + dhcp_msg->ciaddr = iface->ciaddr; + else + p = fill_requested_ipaddr (iface, p); + } + p = fill_lease_time (&lease_time, p); + p = fill_param_request (p); + p = fill_host_and_class_id (iface, p); + *p = endOption; + + /* build UDP/IP header */ + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id); + + return (udp_msg); +} +/*****************************************************************************/ +udpipMessage *buildDhcpRequest(dhcp_interface *iface) +{ + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + register unsigned char *p = dhcp_msg->options + 4; + + fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); + p = fill_message_type (DHCP_REQUEST, p); + p = fill_server_id (iface->dhcp_options.val[dhcpServerIdentifier], p); + if ( iface->client_options->do_rfc1541 ) + dhcp_msg->ciaddr = iface->ciaddr; + else + p = fill_requested_ipaddr (iface, p); + if ( iface->dhcp_options.val[dhcpIPaddrLeaseTime] ) + p = fill_lease_time (iface->dhcp_options.val[dhcpIPaddrLeaseTime], p); + p = fill_param_request (p); + p = fill_host_and_class_id (iface, p); + *p = endOption; + + /* build UDP/IP header */ + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id); + + return udp_msg; +} +/*****************************************************************************/ +udpipMessage *buildDhcpRenew(dhcp_interface *iface) +{ + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + register unsigned char *p = dhcp_msg->options + 4; + + fill_common_fields (iface, udp_msg, iface->shaddr, 1); + dhcp_msg->ciaddr = iface->ciaddr; + p = fill_message_type (DHCP_REQUEST, p); +#if 0 + if ( iface->dhcp_options.val[dhcpIPaddrLeaseTime] ) + p = fill_lease_time (iface->dhcp_options.val[dhcpIPaddrLeaseTime], p); +#endif + p = fill_param_request (p); + p = fill_host_and_class_id (iface, p); + *p = endOption; + + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), iface->ciaddr, iface->siaddr, &iface->ip_id); + + return (udp_msg); +} +/*****************************************************************************/ +udpipMessage *buildDhcpRebind(dhcp_interface *iface) +{ + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + register unsigned char *p = dhcp_msg->options + 4; + + fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); + dhcp_msg->ciaddr = iface->ciaddr; + p = fill_message_type (DHCP_REQUEST, p); + if ( iface->dhcp_options.val[dhcpIPaddrLeaseTime] ) + p = fill_lease_time (iface->dhcp_options.val[dhcpIPaddrLeaseTime], p); + p = fill_param_request (p); + p = fill_host_and_class_id (iface, p); + *p = endOption; + + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), iface->ciaddr, INADDR_BROADCAST, &iface->ip_id); + + return udp_msg; +} +/*****************************************************************************/ +udpipMessage *buildDhcpReboot(dhcp_interface *iface) +{ + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + register unsigned char *p = dhcp_msg->options + 4; + unsigned int lease_time = htonl (iface->default_lease_time); + + fill_common_fields (iface, udp_msg, MAC_BCAST_ADDR, 1); + p = fill_message_type (DHCP_REQUEST, p); + if ( iface->client_options->do_rfc1541 ) + dhcp_msg->ciaddr = iface->ciaddr; + else + p = fill_requested_ipaddr (iface, p); + p = fill_lease_time (&lease_time, p); + p = fill_param_request (p); + p = fill_host_and_class_id (iface, p); + *p = endOption; + + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id); + + return (udp_msg); +} +/*****************************************************************************/ +udpipMessage *buildDhcpRelease(dhcp_interface *iface) +{ + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + register unsigned char *p = dhcp_msg->options + 4; + + fill_common_fields (iface, udp_msg, iface->shaddr, 1); + dhcp_msg->ciaddr = iface->ciaddr; + *p++ = dhcpMessageType; + *p++ = 1; + *p++ = DHCP_RELEASE; + p = fill_server_id (iface->dhcp_options.val[dhcpServerIdentifier], p); + memcpy(p, iface->cli_id, iface->cli_id_len); + p += iface->cli_id_len; + *p = endOption; + + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), iface->ciaddr, iface->siaddr, &iface->ip_id); + + return (udp_msg); +} +/*****************************************************************************/ +#ifdef ARPCHECK +udpipMessage *buildDhcpDecline(dhcp_interface *iface) +{ + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + register unsigned char *p = dhcp_msg->options + 4; + + fill_common_fields (iface, udp_msg, iface->shaddr, 1); + *p++ = dhcpMessageType; + *p++ = 1; + *p++ = DHCP_DECLINE; + p = fill_server_id (iface->dhcp_options.val[dhcpServerIdentifier], p); + if ( iface->client_options->do_rfc1541 ) + dhcp_msg->ciaddr = iface->ciaddr; + else + p = fill_requested_ipaddr (iface, p); + memcpy (p, iface->cli_id, iface->cli_id_len); + p += iface->cli_id_len; + *p = endOption; + + udpipgen ((udpiphdr *)(udp_msg->udpipmsg), 0, iface->siaddr, &iface->ip_id); + + return (udp_msg); +} +#endif +/*****************************************************************************/ +udpipMessage *buildDhcpInform(dhcp_interface *iface) +{ + udpipMessage *udp_msg = calloc (1, sizeof (udpipMessage)); + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + register unsigned char *p = dhcp_msg->options + 4; + + fill_common_fields (iface, udp_msg, iface->shaddr, 1); + dhcp_msg->ciaddr = iface->ciaddr; + p = fill_message_type (DHCP_INFORM, p); + p = fill_param_request (p); + p = fill_host_and_class_id (iface, p); + *p = endOption; + + udpipgen((udpiphdr *)(udp_msg->udpipmsg), 0, INADDR_BROADCAST, &iface->ip_id); + + return (udp_msg); +} diff --git a/dhcpcd/buildmsg.h b/dhcpcd/buildmsg.h new file mode 100644 index 0000000000..96c0300735 --- /dev/null +++ b/dhcpcd/buildmsg.h @@ -0,0 +1,35 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 BUILDMSG_H +#define BUILDMSG_H + +udpipMessage *buildDhcpDiscover(dhcp_interface *iface); +udpipMessage *buildDhcpRequest(dhcp_interface *iface); +udpipMessage *buildDhcpRenew(dhcp_interface *iface); +udpipMessage *buildDhcpRebind(dhcp_interface *iface); +udpipMessage *buildDhcpReboot(dhcp_interface *iface); +udpipMessage *buildDhcpRelease(dhcp_interface *iface); +udpipMessage *buildDhcpDecline(dhcp_interface *iface); +udpipMessage *buildDhcpInform(dhcp_interface *iface); + +#endif diff --git a/dhcpcd/client.c b/dhcpcd/client.c new file mode 100644 index 0000000000..146518fe14 --- /dev/null +++ b/dhcpcd/client.c @@ -0,0 +1,1179 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "client.h" +#include "buildmsg.h" +#include "udpipgen.h" +#include "arp.h" + +int DebugFlag = 1; +#define DEBUG + +void debug_dump_dhcp_options (udpipMessage *udp_msg, dhcpOptions *options); + +/*****************************************************************************/ +int parseDhcpMsgRecv(udpipMessage *udp_msg, dhcpOptions *options) /* this routine parses dhcp message received */ +{ + const struct ip *ip_msg = (struct ip *)((struct udpiphdr *)udp_msg->udpipmsg)->ip; + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + register u_char *p = dhcp_msg->options+4; + unsigned char *end = dhcp_msg->options + sizeof(dhcp_msg->options); + + /* Force T1 and T2 to 0: either new values will be in message, or they + will need to be recalculated from lease time */ + if ( options->val[dhcpT1value] && options->len[dhcpT1value] > 0 ) + memset (options->val[dhcpT1value], 0, options->len[dhcpT1value]); + if ( options->val[dhcpT2value] && options->len[dhcpT2value] > 0 ) + memset (options->val[dhcpT2value], 0, options->len[dhcpT2value]); + + while ( p < end ) + { + switch ( *p ) + { + case endOption: + goto swend; + case padOption: + p++; + break; + default: + if ( p[1] ) + { + if ( options->len[*p] == p[1] ) + memcpy (options->val[*p], p+2, p[1]); + else + { + options->len[*p] = p[1]; + if ( options->val[*p] ) + free (options->val[*p]); + else + options->num++; + options->val[*p] = malloc (p[1]+1); + memset (options->val[*p], 0, p[1]+1); + memcpy (options->val[*p], p+2, p[1]); + } + } + p+=p[1]+2; + } + } + +swend: +#ifdef DEBUG + debug_dump_dhcp_options (udp_msg, options); +#endif + +#if 0 + if ( ! dhcp_msg->yiaddr ) + dhcp_msg->yiaddr = DhcpMsgSend->ciaddr; +#endif + + if ( ! options->val[dhcpServerIdentifier] ) /* did not get dhcpServerIdentifier */ + { + /* make it the same as IP address of the sender */ + options->val[dhcpServerIdentifier] = malloc(4); + memcpy (options->val[dhcpServerIdentifier], &ip_msg->ip_src.s_addr, 4); + options->len[dhcpServerIdentifier] = 4; + options->num++; + if ( DebugFlag ) + syslog(LOG_DEBUG, "dhcpServerIdentifier option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", + ((unsigned char *)options->val[dhcpServerIdentifier])[0], + ((unsigned char *)options->val[dhcpServerIdentifier])[1], + ((unsigned char *)options->val[dhcpServerIdentifier])[2], + ((unsigned char *)options->val[dhcpServerIdentifier])[3]); + } + if ( ! options->val[dns] ) /* did not get DNS */ + { + /* make it the same as dhcpServerIdentifier */ + options->val[dns] = malloc(4); + memcpy (options->val[dns], options->val[dhcpServerIdentifier], 4); + options->len[dns] = 4; + options->num++; + if ( DebugFlag ) + syslog(LOG_DEBUG, "dns option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", + ((unsigned char *)options->val[dns])[0], + ((unsigned char *)options->val[dns])[1], + ((unsigned char *)options->val[dns])[2], + ((unsigned char *)options->val[dns])[3]); + } + if ( ! options->val[subnetMask] ) /* did not get subnetMask */ + { + options->val[subnetMask] = malloc(4); + ((unsigned char *)options->val[subnetMask])[0] = 255; + if ( IN_CLASSA(ntohl(dhcp_msg->yiaddr)) ) + { + ((unsigned char *)options->val[subnetMask])[1] = 0; /* class A */ + ((unsigned char *)options->val[subnetMask])[2] = 0; + ((unsigned char *)options->val[subnetMask])[3] = 0; + } + else + { + ((unsigned char *)options->val[subnetMask])[1] = 255; + if ( IN_CLASSB(ntohl(dhcp_msg->yiaddr)) ) + { + ((unsigned char *)(options->val[subnetMask]))[2] = 0;/* class B */ + ((unsigned char *)(options->val[subnetMask]))[3] = 0; + } + else + { + ((unsigned char *)options->val[subnetMask])[2] = 255; + if ( IN_CLASSC(ntohl(dhcp_msg->yiaddr)) ) + ((unsigned char *)options->val[subnetMask])[3] = 0; /* class C */ + else + ((unsigned char *)options->val[subnetMask])[3] = 255; + } + } + options->len[subnetMask] = 4; + options->num++; + if ( DebugFlag ) + syslog(LOG_DEBUG, "subnetMask option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", + ((unsigned char *)options->val[subnetMask])[0], + ((unsigned char *)options->val[subnetMask])[1], + ((unsigned char *)options->val[subnetMask])[2], + ((unsigned char *)options->val[subnetMask])[3]); + } + if ( ! options->val[broadcastAddr] ) /* did not get broadcastAddr */ + { + int br = dhcp_msg->yiaddr | ~*((int *)options->val[subnetMask]); + options->val[broadcastAddr] = malloc(4); + memcpy (options->val[broadcastAddr], &br, 4); + options->len[broadcastAddr] = 4; + options->num++; + if ( DebugFlag ) + syslog(LOG_DEBUG, "broadcastAddr option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", + ((unsigned char *)options->val[broadcastAddr])[0], + ((unsigned char *)options->val[broadcastAddr])[1], + ((unsigned char *)options->val[broadcastAddr])[2], + ((unsigned char *)options->val[broadcastAddr])[3]); + } +#if 0 + if ( ! options->val[routersOnSubnet] ) + { + options->val[routersOnSubnet] = malloc(4); + if ( dhcp_msg->giaddr ) + memcpy(options->val[routersOnSubnet],&dhcp_msg->giaddr,4); + else + memcpy(options->val[routersOnSubnet],options->val[dhcpServerIdentifier],4); + options->len[routersOnSubnet] = 4; + options->num++; + if ( DebugFlag ) + syslog(LOG_DEBUG, "routersOnSubnet option is missing in DHCP server response. Assuming %u.%u.%u.%u\n", + ((unsigned char *)options->val[routersOnSubnet])[0], + ((unsigned char *)options->val[routersOnSubnet])[1], + ((unsigned char *)options->val[routersOnSubnet])[2], + ((unsigned char *)options->val[routersOnSubnet])[3]); + } +#endif + if ( options->val[dhcpIPaddrLeaseTime] && options->len[dhcpIPaddrLeaseTime] == 4 ) + { + if ( *(unsigned int *)options->val[dhcpIPaddrLeaseTime] == 0 ) + { + unsigned int lease_time = htonl (DHCP_DEFAULT_LEASETIME); + memcpy (options->val[dhcpIPaddrLeaseTime], &lease_time, 4); + if ( DebugFlag ) + syslog(LOG_DEBUG,"dhcpIPaddrLeaseTime=0 in DHCP server response. Assuming %u sec\n", lease_time); + } + else + { + if ( DebugFlag ) + syslog(LOG_DEBUG,"dhcpIPaddrLeaseTime = %u in DHCP server response.\n", + ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime])); + } + } + else /* did not get dhcpIPaddrLeaseTime */ + { + unsigned int lease_time = htonl (DHCP_DEFAULT_LEASETIME); + options->val[dhcpIPaddrLeaseTime] = malloc(4); + memcpy (options->val[dhcpIPaddrLeaseTime], &lease_time, 4); + options->len[dhcpIPaddrLeaseTime] = 4; + options->num++; + if ( DebugFlag ) + syslog(LOG_DEBUG,"dhcpIPaddrLeaseTime option is missing in DHCP server response. Assuming %u sec\n", lease_time); + } + if ( options->val[dhcpT1value] && options->len[dhcpT1value] == 4 ) + { + if ( *(unsigned int *)options->val[dhcpT1value] == 0 ) + { + unsigned t2 = 0.5 * ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); + int t1 = htonl(t2); + memcpy (options->val[dhcpT1value],&t1,4); + options->len[dhcpT1value] = 4; + if ( DebugFlag ) + syslog(LOG_DEBUG,"dhcpT1value is missing in DHCP server response. Assuming %u sec\n",t2); + } + } + else /* did not get T1 */ + { + unsigned t2 = 0.5*ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); + int t1 = htonl(t2); + options->val[dhcpT1value] = malloc(4); + memcpy (options->val[dhcpT1value],&t1,4); + options->len[dhcpT1value] = 4; + options->num++; + if ( DebugFlag ) + syslog(LOG_DEBUG,"dhcpT1value is missing in DHCP server response. Assuming %u sec\n",t2); + } + if ( options->val[dhcpT2value] && options->len[dhcpT2value] == 4 ) + { + if ( *(unsigned int *)options->val[dhcpT2value] == 0 ) + { + unsigned t2 = 0.875*ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); + int t1 = htonl(t2); + memcpy(options->val[dhcpT2value],&t1,4); + options->len[dhcpT2value] = 4; + if ( DebugFlag ) + syslog(LOG_DEBUG,"dhcpT2value is missing in DHCP server response. Assuming %u sec\n",t2); + } + } + else /* did not get T2 */ + { + unsigned t2 = 0.875*ntohl(*(unsigned int *)options->val[dhcpIPaddrLeaseTime]); + int t1 = htonl(t2); + options->val[dhcpT2value] = malloc(4); + memcpy(options->val[dhcpT2value],&t1,4); + options->len[dhcpT2value] = 4; + options->num++; + if ( DebugFlag ) + syslog(LOG_DEBUG,"dhcpT2value is missing in DHCP server response. Assuming %u sec\n",t2); + } + if ( options->val[dhcpMessageType] ) + return *(unsigned char *)options->val[dhcpMessageType]; + return -1; +} +/*****************************************************************************/ +void classIDsetup(dhcp_interface *iface, const char *g_cls_id) +{ + unsigned int g_cls_id_len = 0; + + if (!iface) return; + + if (g_cls_id) + g_cls_id_len = strlen (g_cls_id); + + if (g_cls_id_len) + { + memcpy (iface->cls_id, g_cls_id, g_cls_id_len); + iface->cls_id_len = g_cls_id_len; + } + else + { + struct utsname sname; + if ( uname(&sname) ) + syslog(LOG_ERR,"classIDsetup: uname: %m\n"); + snprintf (iface->cls_id, DHCP_CLASS_ID_MAX_LEN, "%s %s %s", + sname.sysname, sname.release, sname.machine); + } +} +/*****************************************************************************/ +void clientIDsetup(dhcp_interface *iface, const char *g_cli_id) +{ + unsigned int g_cli_id_len = 0; + unsigned char *c = iface->cli_id; + + if (!iface) return; + + if (g_cli_id) + g_cli_id_len = strlen (g_cli_id); + + *c++ = dhcpClientIdentifier; + if ( g_cli_id_len ) + { + *c++ = g_cli_id_len + 1; /* 1 for the field below */ + *c++ = 0; /* type: string */ + memcpy (c, g_cli_id, g_cli_id_len); + iface->cli_id_len = g_cli_id_len + 3; + } + else + { + *c++ = ETH_ALEN + 1; /* length: 6 (MAC Addr) + 1 (# field) */ + *c++ = (iface->bTokenRing) ? ARPHRD_IEEE802_TR : ARPHRD_ETHER; /* type: Ethernet address */ + memcpy (c, iface->chaddr, ETH_ALEN); + iface->cli_id_len = ETH_ALEN + 3; + } +} +/*****************************************************************************/ +void releaseDhcpOptions (dhcp_interface *iface) +{ + register int i; + for ( i = 1; i < 256; i++ ) + { + if ( iface->dhcp_options.val[i] ) + free(iface->dhcp_options.val[i]); + } + + memset(&(iface->dhcp_options), 0, sizeof(dhcpOptions)); +} +/*****************************************************************************/ +#ifdef DEBUG +static void dumpframe(const char *title, struct packed_ether_header *frame) +{ + int i; + unsigned char *dp; + + printf("%s:", title); + dp = (unsigned char *)frame; + for (i = 0; i < 32; i++) + { + if ((i % 16) == 0) + printf("\n"); + printf("0x%02X ", *dp++); + } +} +#endif /* DEBUG */ +/*****************************************************************************/ +/***** convert ethernet and token-ring frames *****/ +int eth2tr(struct packed_ether_header *frame, int datalen) +{ + struct trh_hdr *phdr; + struct trllc *pllc; + char trheader[sizeof(struct trh_hdr) - sizeof(phdr->rseg) + sizeof(struct trllc)]; + int len; + +#ifdef DEBUG + dumpframe("eth2tr: Incoming eth frame", frame); +#endif + memset(trheader, 0, sizeof(trheader)); + phdr = (struct trh_hdr *)trheader; + phdr->ac = AC; + phdr->fc = LLC_FRAME; + memcpy(phdr->daddr, frame->ether_dhost, TR_ALEN); + memcpy(phdr->saddr, frame->ether_shost, TR_ALEN); + if (phdr->daddr[0] & 0x80) + { /* Destination is a broadcast */ + phdr->rcf = sizeof(phdr->rcf) | htons(TR_RCF_BROADCAST | 0x70); /* Unlimited frame length */ + pllc = (struct trllc *)&phdr->rseg[0]; + phdr->saddr[0] |= TR_RII; /* Set source-route indicator */ + len = sizeof(trheader); + } + else + { + pllc = (struct trllc *)&phdr->rcf; + len = sizeof(trheader) - sizeof(phdr->rcf); + } + pllc->dsap = EXTENDED_SAP; + pllc->ssap = EXTENDED_SAP; + pllc->llc = UI_CMD; + pllc->protid[0] = pllc->protid[1] = pllc->protid[2] = 0; + pllc->ethertype = frame->ether_type; + /* Make room for larger TR header */ + memmove((char *)(frame + 1) + (len - sizeof(struct packed_ether_header)), frame + 1, datalen); + memcpy(frame, trheader, len); /* Install TR header */ +#ifdef DEBUG + dumpframe("eth2tr: Outgoing tr frame", frame); +#endif + return len + datalen; +} +/*****************************************************************************/ +int tr2eth(struct packed_ether_header *frame) +{ + struct trh_hdr hdr; + struct trllc *pllc; + int hlen = 0; + +#ifdef DEBUG + dumpframe("tr2eth: Incoming tr frame", frame); +#endif + hdr = *((struct trh_hdr *)frame); + if (hdr.saddr[0] & TR_RII) + { + fake_rif: + hlen = hdr.rcf & ntohs(TR_RCF_LEN_MASK); + #ifdef DEBUG + printf("rcf = 0x%X SR len %d\n", hdr.rcf, hlen); + #endif + if (hlen < sizeof(hdr.rcf) || (hlen & 1)) + return 1; + hdr.saddr[0] &= ~TR_RII; + } + pllc = (struct trllc *)(((__u8 *)frame) + sizeof(struct trh_hdr) - TR_MAXRIFLEN + hlen); + if (pllc->dsap != EXTENDED_SAP || pllc->llc != UI_CMD) + { + if (hlen == 0) + goto fake_rif; /* Bug in 2.2.3 kernel */ + #ifdef DEBUG + printf("corrupted TR-IP packet of ui=0x%x and dsap 0x%x discarded\n", pllc->llc, pllc->dsap); + #endif + return 1; + } + memcpy(frame->ether_dhost, hdr.daddr, ETH_ALEN); + memcpy(frame->ether_shost, hdr.saddr, ETH_ALEN); + frame->ether_type = pllc->ethertype; + memmove(frame + 1, pllc + 1, IPPACKET_SIZE); /* Move data portion: Overlapping buffer */ +#ifdef DEBUG + dumpframe("tr2eth: Outgoing eth frame", frame); +#endif + return 0; +} +/*****************************************************************************/ +/* Subtract the `struct timeval' values X and Y, + storing the result in RESULT. + Return 1 if the difference is negative, otherwise 0. */ +static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) +{ + /* Perform the carry for the later subtraction by updating Y. */ + if (x->tv_usec < y->tv_usec) + { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) + { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + + /* Compute the time remaining to wait. + `tv_usec' is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} +/*****************************************************************************/ +int peekfd (dhcp_interface *iface, time_t tv_usec) +{ + fd_set fs; + struct timeval begin; + time_t i = tv_usec; + + FD_ZERO (&fs); + FD_SET (iface->sk, &fs); + gettimeofday (&begin, NULL); + + /* Wake up each second to check whether or not we've been told + * to stop with iface->cease + */ + while (i > 0) + { + struct timeval now; + struct timeval diff; + struct timeval wait = {1, 0}; + + if ( select (iface->sk+1, &fs, NULL, NULL, &wait) == -1 ) + return RET_DHCP_ERROR; + if ( FD_ISSET(iface->sk, &fs) ) + return RET_DHCP_SUCCESS; + gettimeofday (&now, NULL); + timeval_subtract (&diff, &now, &begin); + i = tv_usec - ((diff.tv_sec * 1000000) + diff.tv_usec); + if (iface->cease) + return RET_DHCP_CEASED; + } + return RET_DHCP_TIMEOUT; +} +/*****************************************************************************/ +int dhcpSendAndRecv (dhcp_interface *iface, unsigned int expected_reply_type, + dhcp_msg_build_proc buildUdpIpMsg, udpipMessage **return_msg) +{ + udpipMessage *udp_msg_recv = NULL; + struct sockaddr addr; + int len, err, local_timeout = 0; + int j = DHCP_INITIAL_RTO / 2; + struct timeval local_begin, current, diff; + struct timeval overall_end; + + *return_msg = NULL; + + gettimeofday (&overall_end, NULL); + overall_end.tv_sec += iface->client_options->base_timeout; + + do + { + udpipMessage *udp_msg_send = buildUdpIpMsg (iface); + + if (!udp_msg_send) + return RET_DHCP_ERROR; + + j += j; + if (j > DHCP_MAX_RTO) + j = DHCP_MAX_RTO; + + /* Make sure waiting j seconds isn't greater than our overall time left + * on this operation, and clamp j to the overall time left if it is. + */ + gettimeofday (¤t, NULL); + if (timeval_subtract (&diff, &overall_end, ¤t)) + { + free (udp_msg_send); + return RET_DHCP_TIMEOUT; + } + if (j > ((diff.tv_sec * 1000000) + diff.tv_usec)) + j = (diff.tv_sec * 1000000) + diff.tv_usec; + + if (iface->bTokenRing) /* Here we convert a Eth frame into an TR frame */ + len = eth2tr (&(udp_msg_send->ethhdr), sizeof(udpiphdr) + sizeof(dhcpMessage)); + else + len = sizeof (struct packed_ether_header) + sizeof(udpiphdr) + sizeof(dhcpMessage); + + memset (&addr, 0, sizeof(struct sockaddr)); + memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); + if (sendto (iface->sk, udp_msg_send, len, 0, &addr, sizeof(struct sockaddr)) == -1) + { + syslog (LOG_ERR,"sendto: %m\n"); + free (udp_msg_send); + return RET_DHCP_ERROR; + } + free (udp_msg_send); + gettimeofday (&local_begin, NULL); + err = peekfd (iface, (j + random () % 200000)); + if (iface->cease || (err == RET_DHCP_CEASED)) + return RET_DHCP_CEASED; + } while ( err == RET_DHCP_TIMEOUT ); + + do + { + struct ip ipRecv_local; + char *tmp_ip; + const struct udphdr *udp_msg_recv_hdr; + dhcpMessage *dhcp_msg_recv; + int reply_type = -1; + char foobuf[512]; + int i, o; + + udp_msg_recv = calloc (1, sizeof (udpipMessage)); + o = sizeof (struct sockaddr); + len = recvfrom (iface->sk, udp_msg_recv, sizeof(udpipMessage), 0, (struct sockaddr *)&addr, &o); + if (len == -1) + { + syslog(LOG_ERR,"recvfrom: %m\n"); + free (udp_msg_recv); + return RET_DHCP_ERROR; + } + + if (iface->bTokenRing) + { /* Here we convert a TR frame into an Eth frame */ + if (tr2eth (&(udp_msg_recv->ethhdr))) + { + free (udp_msg_recv); + continue; + } + } + + gettimeofday (¤t, NULL); + timeval_subtract (&diff, ¤t, &local_begin); + local_timeout = j - diff.tv_sec * 1000000 - diff.tv_usec + random() % 200000; + + /* Make sure waiting local_timeout seconds isn't greater than our overall time left + * on this operation, and clamp local_timeout to the overall time left if it is. + */ + if (timeval_subtract (&diff, &overall_end, ¤t)) + { + free (udp_msg_recv); + return RET_DHCP_TIMEOUT; + } + if ((local_timeout*1000000) > ((diff.tv_sec * 1000000) + diff.tv_usec)) + local_timeout = (diff.tv_sec * 1000000) + diff.tv_usec; + + /* Ignore non-IP packets */ + if ( udp_msg_recv->ethhdr.ether_type != htons(ETHERTYPE_IP) ) + { + free (udp_msg_recv); + continue; + } + + tmp_ip = udp_msg_recv->udpipmsg; + for (i = 0; i < sizeof (struct ip) - 2; i += 2) + { + if ( ( udp_msg_recv->udpipmsg[i] == 0x45 ) && ( udp_msg_recv->udpipmsg[i+1] == 0x00 ) ) + { + tmp_ip = &(udp_msg_recv->udpipmsg[i]); + break; + } + } + + /* Use local copy because ipRecv is not aligned. */ + memcpy (&ipRecv_local, ((struct udpiphdr *)tmp_ip)->ip, sizeof(struct ip)); + udp_msg_recv_hdr = (struct udphdr *)((char*)(((struct udpiphdr*)tmp_ip)->ip)+sizeof(struct ip)); + if ( ipRecv_local.ip_p != IPPROTO_UDP ) + { + free (udp_msg_recv); + continue; + } + + if ( iface->bTokenRing && (udp_msg_recv_hdr->uh_dport != htons(DHCP_CLIENT_PORT))) + { + free (udp_msg_recv); + continue; + } + + len -= sizeof(struct packed_ether_header); + i = (int)ntohs (ipRecv_local.ip_len); + if ( len < i ) + { + if ( DebugFlag ) + syslog(LOG_DEBUG, "corrupted IP packet of size=%d and ip_len=%d discarded\n", len,i); + free (udp_msg_recv); + continue; + } + + len = i - (ipRecv_local.ip_hl << 2); + i = (int)ntohs(udp_msg_recv_hdr->uh_ulen); + if ( len < i ) + { + if ( DebugFlag ) + syslog(LOG_DEBUG, "corrupted UDP msg of size=%d and uh_ulen=%d discarded\n", len,i); + free (udp_msg_recv); + continue; + } + + if ( iface->client_options->do_checksum && (len = udpipchk((udpiphdr *)tmp_ip))) + { + if ( DebugFlag ) + { + switch ( len ) + { + case -1: + syslog(LOG_DEBUG, "corrupted IP packet with ip_len=%d discarded\n", (int)ntohs(ipRecv_local.ip_len)); + break; + case -2: + syslog(LOG_DEBUG, "corrupted UDP msg with uh_ulen=%d discarded\n", (int)ntohs(udp_msg_recv_hdr->uh_ulen)); + break; + } + } + free (udp_msg_recv); + continue; + } + + dhcp_msg_recv = (dhcpMessage *)&(tmp_ip[(ipRecv_local.ip_hl << 2) + sizeof(struct udphdr)]); + if ( dhcp_msg_recv->xid != iface->xid ) + { + free (udp_msg_recv); + continue; + } + + if ( dhcp_msg_recv->htype != ARPHRD_ETHER && dhcp_msg_recv->htype != (char)ARPHRD_IEEE802_TR ) + { + if ( DebugFlag ) + syslog (LOG_DEBUG,"wrong msg htype 0x%X discarded\n", dhcp_msg_recv->htype); + free (udp_msg_recv); + continue; + } + + if ( dhcp_msg_recv->op != DHCP_BOOTREPLY ) + { + free (udp_msg_recv); + continue; + } + + while ((iface->foo_sk > 0) && recvfrom (iface->foo_sk, (void *)foobuf, sizeof(foobuf), 0, NULL, NULL) != -1); + + /* Copy DHCP response options from received packet into local options list */ + reply_type = parseDhcpMsgRecv (udp_msg_recv, &(iface->dhcp_options)); + if ( expected_reply_type == reply_type ) + { + *return_msg = udp_msg_recv; + return RET_DHCP_SUCCESS; + } + + free (udp_msg_recv); + udp_msg_recv = NULL; + + if (reply_type == DHCP_NAK) + { + if ( iface->dhcp_options.val[dhcpMsg] ) + syslog(LOG_ERR, "DHCP_NAK server response received: %s\n", (char *)iface->dhcp_options.val[dhcpMsg]); + else + syslog(LOG_ERR, "DHCP_NAK server response received\n"); + return RET_DHCP_NAK; + } + + err = peekfd (iface, local_timeout); + if (iface->cease || (err == RET_DHCP_CEASED)) + return RET_DHCP_CEASED; + } while ((local_timeout > 0) && (err == RET_DHCP_SUCCESS)); + + return RET_DHCP_TIMEOUT; +} +/*****************************************************************************/ +int dhcp_reboot (dhcp_interface *iface) +{ + /* Client has a cached IP and wants to request it again from the server + * if possible. DHCP state INIT-REBOOT. + * + * If no response from the server is received, we assume that we can still + * use the cached IP address. + */ + + /* FIXME: get the IP address to renew from somewhere */ + + if (!iface) return RET_DHCP_ERROR; + + releaseDhcpOptions (iface); + return dhcp_request (iface, &buildDhcpReboot); +} +/*****************************************************************************/ +int dhcp_init (dhcp_interface *iface) +{ + udpipMessage *msg = NULL; + dhcpMessage *dhcp_msg = NULL; + int err; + + if (!iface) return RET_DHCP_ERROR; + + releaseDhcpOptions (iface); + +#ifdef DEBUG + fprintf(stderr,"ClassID = \"%s\"\n" + "ClientID = \"%u.%u.%u.%02X.%02X.%02X.%02X.%02X.%02X\"\n", iface->cls_id, + iface->cli_id[0], iface->cli_id[1], iface->cli_id[2], + iface->cli_id[3], iface->cli_id[4], iface->cli_id[5], + iface->cli_id[6], iface->cli_id[7], iface->cli_id[8]); +#endif + + if ( DebugFlag ) + syslog (LOG_DEBUG,"broadcasting DHCP_DISCOVER\n"); + iface->xid = random (); + err = dhcpSendAndRecv (iface, DHCP_OFFER, &buildDhcpDiscover, &msg); + if (err != RET_DHCP_SUCCESS) + return err; + + dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); + if ( iface->client_options->send_second_discover ) + { + udpipMessage *msg2 = NULL; + + if (DebugFlag) + syslog (LOG_DEBUG,"broadcasting second DHCP_DISCOVER\n"); + + iface->xid = dhcp_msg->xid; + err = dhcpSendAndRecv (iface, DHCP_OFFER, &buildDhcpDiscover, &msg2); + if (err == RET_DHCP_SUCCESS) + { + free (msg); + msg = msg2; + } + dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); + } + + iface->ciaddr = dhcp_msg->yiaddr; + memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4); + memcpy (iface->shaddr, msg->ethhdr.ether_shost, ETH_ALEN); + iface->xid = dhcp_msg->xid; + + /* DHCP_OFFER received */ + if ( DebugFlag ) + { + syslog(LOG_DEBUG,"DHCP_OFFER received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]); + } + free (msg); + + return dhcp_request (iface, &buildDhcpRequest); +} +/*****************************************************************************/ +int dhcp_request(dhcp_interface *iface, dhcp_msg_build_proc buildDhcpMsg) +{ + udpipMessage *msg = NULL; + int err; + + /* DHCP state REQUEST: request an address from a _particular_ DHCP server */ + + if (!iface) return RET_DHCP_ERROR; + + if ( DebugFlag ) + { + syslog(LOG_DEBUG,"broadcasting DHCP_REQUEST for %u.%u.%u.%u\n", + ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]); + } + + err = dhcpSendAndRecv (iface, DHCP_ACK, buildDhcpMsg, &msg); + if (err != RET_DHCP_SUCCESS) + return err; + + if ( DebugFlag ) + { + dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); + syslog(LOG_DEBUG, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]); + } + + iface->req_sent_time = time (NULL); + +#ifdef ARPCHECK + /* check if the offered IP address already in use */ + if ( arpCheck(iface) ) + { + if ( DebugFlag ) + syslog(LOG_DEBUG, "requested %u.%u.%u.%u address is in use\n", + ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]); + dhcpDecline(); + iface->ciaddr = 0; + return RET_DHCP_ADDRESS_IN_USE; + } + + if ( DebugFlag ) + { + syslog(LOG_DEBUG, "verified %u.%u.%u.%u address is not in use\n", + ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]); + } +#endif + + /* Successfull ACK: Use the fields obtained for future requests */ + memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4); + memcpy (iface->shaddr, msg->ethhdr.ether_shost, ETH_ALEN); + free (msg); + + return RET_DHCP_BOUND; +} +/*****************************************************************************/ +#if 0 +int dhcp_bound(dhcp_interface *iface) +{ + int i; + + i = iface->req_sent_time + ntohl(*(unsigned int *)(iface->dhcp_options.val[dhcpT1value])) - time (NULL); + if ( i > 0 ) + alarm(i); + else + return STATE_DHCP_RENEW; + sleep (ntohl(*(u_int *)(iface->dhcp_options.val[dhcpT1value]))); + + return STATE_DHCP_RENEW; +} +#endif +/*****************************************************************************/ +int dhcp_renew(dhcp_interface *iface) +{ + udpipMessage *msg = NULL; + int err; + + /* DHCP state RENEW: request renewal of our lease from the original DHCP server */ + +#if 0 + i = iface->req_sent_time + ntohl(*(unsigned int *)(iface->dhcp_options.val[dhcpT2value])) - time(NULL); +#endif + + if (!iface) return RET_DHCP_ERROR; + + if ( DebugFlag ) + { + syslog(LOG_DEBUG,"sending DHCP_REQUEST for %u.%u.%u.%u to %u.%u.%u.%u\n", + ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3], + ((unsigned char *)&(iface->siaddr))[0], ((unsigned char *)&(iface->siaddr))[1], + ((unsigned char *)&(iface->siaddr))[2], ((unsigned char *)&(iface->siaddr))[3]); + } + + iface->xid = random(); + err = dhcpSendAndRecv (iface, DHCP_ACK, &buildDhcpRenew, &msg); + if (err != RET_DHCP_SUCCESS); + return err; + + iface->req_sent_time = time (NULL); + + if ( DebugFlag ) + { + dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); + syslog(LOG_DEBUG, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]); + } + free (msg); + + return RET_DHCP_BOUND; +} +/*****************************************************************************/ +int dhcp_rebind(dhcp_interface *iface) +{ + udpipMessage *msg = NULL; + int err; + + /* DHCP state REBIND: request renewal of our lease from _any_ DHCP server */ + +#if 0 + i = iface->req_sent_time + ntohl(*(unsigned int *)(iface->dhcp_options.val[dhcpIPaddrLeaseTime])) - time(NULL); +#endif + + if (!iface) return RET_DHCP_ERROR; + + if ( DebugFlag ) + { + syslog(LOG_DEBUG,"broadcasting DHCP_REQUEST for %u.%u.%u.%u\n", + ((unsigned char *)&(iface->ciaddr))[0], + ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], + ((unsigned char *)&(iface->ciaddr))[3]); + } + + iface->xid = random (); + err = dhcpSendAndRecv(iface, DHCP_ACK, &buildDhcpRebind, &msg); + if (err != RET_DHCP_SUCCESS) + return err; + + iface->req_sent_time = time (NULL); + + if ( DebugFlag ) + { + dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); + syslog(LOG_DEBUG, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]); + } + + /* Successfull ACK: Use the fields obtained for future requests */ + memcpy (&(iface->siaddr), iface->dhcp_options.val[dhcpServerIdentifier], 4); + memcpy (iface->shaddr, msg->ethhdr.ether_shost, ETH_ALEN); + free (msg); + + return RET_DHCP_BOUND; +} +/*****************************************************************************/ +int dhcp_release(dhcp_interface *iface) +{ + struct sockaddr addr; + udpipMessage *msg; + + if ( iface->ciaddr == 0 ) + return RET_DHCP_ERROR; + + iface->xid = random(); + if (!(msg = buildDhcpRelease (iface))) + return RET_DHCP_ERROR; + + if (DebugFlag) + { + syslog(LOG_DEBUG,"sending DHCP_RELEASE for %u.%u.%u.%u to %u.%u.%u.%u\n", + ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3], + ((unsigned char *)&(iface->siaddr))[0], ((unsigned char *)&(iface->siaddr))[1], + ((unsigned char *)&(iface->siaddr))[2], ((unsigned char *)&(iface->siaddr))[3]); + } + + memset (&addr, 0, sizeof(struct sockaddr)); + memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); + if ( sendto (iface->sk, msg, sizeof(struct packed_ether_header) + sizeof(udpiphdr) + sizeof(dhcpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 ) + syslog(LOG_ERR,"dhcpRelease: sendto: %m\n"); + free (msg); + + arpRelease (iface); /* clear ARP cache entries for client IP addr */ + iface->ciaddr = 0; + + return RET_DHCP_SUCCESS; +} +/*****************************************************************************/ +#ifdef ARPCHECK +int dhcp_decline(dhcp_interface *iface) +{ + udpipMessage *msg; + struct sockaddr addr; + + iface->xid = random (); + if (!(msg = buildDhcpDecline (iface))) + return RET_DHCP_ERROR; + + memset (&addr, 0, sizeof(struct sockaddr)); + memcpy (addr.sa_data, iface->iface, strlen (iface->iface)); + if ( DebugFlag ) + syslog (LOG_DEBUG,"broadcasting DHCP_DECLINE\n"); + + if ( sendto (iface->sk, msg, sizeof(struct packed_ether_header) + sizeof(udpiphdr)+sizeof(dhcpMessage), 0, &addr, sizeof(struct sockaddr)) == -1 ) + syslog (LOG_ERR,"dhcpDecline: sendto: %m\n"); + free (msg); + + return RET_DHCP_SUCCESS; +} +#endif +/*****************************************************************************/ +int dhcp_inform(dhcp_interface *iface) +{ + udpipMessage *msg = NULL; + int err; + + if ( DebugFlag ) + { + syslog(LOG_DEBUG, "broadcasting DHCP_INFORM for %u.%u.%u.%u\n", + ((unsigned char *)&(iface->ciaddr))[0], + ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], + ((unsigned char *)&(iface->ciaddr))[3]); + } + + iface->xid = random (); + err = dhcpSendAndRecv (iface, DHCP_ACK, buildDhcpInform, &msg); + if (err != RET_DHCP_SUCCESS) + return err; + + if ( DebugFlag ) + { + dhcpMessage *dhcp_msg = (dhcpMessage *)&(msg->udpipmsg[sizeof(udpiphdr)]); + syslog(LOG_DEBUG, "DHCP_ACK received from %s (%u.%u.%u.%u)\n", dhcp_msg->sname, + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[0], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[1], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[2], + ((unsigned char *)(iface->dhcp_options.val[dhcpServerIdentifier]))[3]); + } + free (msg); + +#ifdef ARPCHECK + /* check if the offered IP address already in use */ + if ( arpCheck(iface) ) + { + if ( DebugFlag ) + syslog(LOG_DEBUG, "requested %u.%u.%u.%u address is in use\n", + ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]); + dhcpDecline (iface); + return RET_DHCP_SUCCESS; + } + if ( DebugFlag ) + { + syslog(LOG_DEBUG, "verified %u.%u.%u.%u address is not in use\n", + ((unsigned char *)&(iface->ciaddr))[0], ((unsigned char *)&(iface->ciaddr))[1], + ((unsigned char *)&(iface->ciaddr))[2], ((unsigned char *)&(iface->ciaddr))[3]); + } +#endif + + return RET_DHCP_SUCCESS; +} + +/*****************************************************************************/ +char *get_dhcp_option_name (int i) +{ + char *buf = NULL; + if (i <= dhcpClientIdentifier) + buf = strdup (dhcp_opt_table [i].name); + else + buf = strdup ("unknown"); + return buf; +} + +/*****************************************************************************/ +void debug_dump_dhcp_options (udpipMessage *udp_msg, dhcpOptions *options) +{ + int i,j; + dhcpMessage *dhcp_msg = (dhcpMessage *)&(udp_msg->udpipmsg[sizeof(udpiphdr)]); + + fprintf (stderr,"parseDhcpMsgRecv: %d options received:\n", options->num); + for (i = 1; i < 255; i++) + { + if ( options->val[i] ) + { + switch ( i ) + { + case 1: /* subnet mask */ + case 3: /* routers on subnet */ + case 4: /* time servers */ + case 5: /* name servers */ + case 6: /* dns servers */ + case 28:/* broadcast addr */ + case 33:/* staticRoute */ + case 41:/* NIS servers */ + case 42:/* NTP servers */ + case 50:/* dhcpRequestdIPaddr */ + case 54:/* dhcpServerIdentifier */ + for (j = 0; j < options->len[i]; j += 4) + { + char *opt_name = get_dhcp_option_name (i); + fprintf (stderr,"i=%-2d (%s) len=%-2d option = %u.%u.%u.%u\n", + i, opt_name, options->len[i], + ((unsigned char *)options->val[i])[0+j], + ((unsigned char *)options->val[i])[1+j], + ((unsigned char *)options->val[i])[2+j], + ((unsigned char *)options->val[i])[3+j]); + free (opt_name); + } + break; + case 2: /* time offset */ + case 51:/* dhcpAddrLeaseTime */ + case 57:/* dhcpMaxMsgSize */ + case 58:/* dhcpT1value */ + case 59:/* dhcpT2value */ + { + char *opt_name = get_dhcp_option_name (i); + fprintf (stderr,"i=%-2d (%s) len=%-2d option = %d\n", i, opt_name, + options->len[i], ntohl(*(int *)options->val[i])); + free (opt_name); + } + break; + case 23:/* defaultIPTTL */ + case 29:/* performMaskdiscovery */ + case 31:/* performRouterdiscovery */ + case 53:/* dhcpMessageType */ + { + char *opt_name = get_dhcp_option_name (i); + fprintf(stderr,"i=%-2d (%s) len=%-2d option = %u\n", i, opt_name, + options->len[i],*(unsigned char *)options->val[i]); + free (opt_name); + } + break; + default: + { + char *opt_name = get_dhcp_option_name (i); + fprintf(stderr,"i=%-2d (%s) len=%-2d option = \"%s\"\n", + i, opt_name, options->len[i], (char *)options->val[i]); + free (opt_name); + } + break; + } + } + } + + fprintf(stderr,"dhcp_msg->yiaddr = %u.%u.%u.%u\n" + "dhcp_msg->siaddr = %u.%u.%u.%u\n" + "dhcp_msg->giaddr = %u.%u.%u.%u\n" + "dhcp_msg->sname = \"%s\"\n" + "ServerHardwareAddr = %02X.%02X.%02X.%02X.%02X.%02X\n", + ((unsigned char *)&dhcp_msg->yiaddr)[0], ((unsigned char *)&dhcp_msg->yiaddr)[1], + ((unsigned char *)&dhcp_msg->yiaddr)[2], ((unsigned char *)&dhcp_msg->yiaddr)[3], + ((unsigned char *)&dhcp_msg->siaddr)[0], ((unsigned char *)&dhcp_msg->siaddr)[1], + ((unsigned char *)&dhcp_msg->siaddr)[2], ((unsigned char *)&dhcp_msg->siaddr)[3], + ((unsigned char *)&dhcp_msg->giaddr)[0], ((unsigned char *)&dhcp_msg->giaddr)[1], + ((unsigned char *)&dhcp_msg->giaddr)[2], ((unsigned char *)&dhcp_msg->giaddr)[3], + dhcp_msg->sname, + udp_msg->ethhdr.ether_shost[0], udp_msg->ethhdr.ether_shost[1], + udp_msg->ethhdr.ether_shost[2], udp_msg->ethhdr.ether_shost[3], + udp_msg->ethhdr.ether_shost[4], udp_msg->ethhdr.ether_shost[5]); +} + diff --git a/dhcpcd/client.h b/dhcpcd/client.h new file mode 100644 index 0000000000..4f67eeff23 --- /dev/null +++ b/dhcpcd/client.h @@ -0,0 +1,286 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 CLIENT_H +#define CLIENT_H + +#include +#include +#include +#include +#include "dhcpcd.h" + + +#define IPPACKET_SIZE 1500 +#define MAGIC_COOKIE 0x63825363 +#define BROADCAST_FLAG 0x8000 +#define MAC_BCAST_ADDR "\xff\xff\xff\xff\xff\xff" +#ifndef AF_PACKET +#define AF_PACKET 17 /* should have been in socketbits.h */ +#endif +#define HWADDR_TRIES 3 + +/* UDP port numbers for DHCP */ +#define DHCP_SERVER_PORT 67 /* from client to server */ +#define DHCP_CLIENT_PORT 68 /* from server to client */ + +/* DHCP message OP code */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message type */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 +/* DHCP RETRANSMISSION TIMEOUT (microseconds) */ +#define DHCP_INITIAL_RTO (4*1000000) +#define DHCP_MAX_RTO (64*1000000) + +/* DHCP option and value (cf. RFC1533) */ +enum +{ + padOption = 0, + subnetMask = 1, + timerOffset = 2, + routersOnSubnet = 3, + timeServer = 4, + nameServer = 5, + dns = 6, + logServer = 7, + cookieServer = 8, + lprServer = 9, + impressServer = 10, + resourceLocationServer = 11, + hostName = 12, + bootFileSize = 13, + meritDumpFile = 14, + domainName = 15, + swapServer = 16, + rootPath = 17, + extentionsPath = 18, + IPforwarding = 19, + nonLocalSourceRouting = 20, + policyFilter = 21, + maxDgramReasmSize = 22, + defaultIPTTL = 23, + pathMTUagingTimeout = 24, + pathMTUplateauTable = 25, + ifMTU = 26, + allSubnetsLocal = 27, + broadcastAddr = 28, + performMaskDiscovery = 29, + maskSupplier = 30, + performRouterDiscovery = 31, + routerSolicitationAddr = 32, + staticRoute = 33, + trailerEncapsulation = 34, + arpCacheTimeout = 35, + ethernetEncapsulation = 36, + tcpDefaultTTL = 37, + tcpKeepaliveInterval = 38, + tcpKeepaliveGarbage = 39, + nisDomainName = 40, + nisServers = 41, + ntpServers = 42, + vendorSpecificInfo = 43, + netBIOSnameServer = 44, + netBIOSdgramDistServer = 45, + netBIOSnodeType = 46, + netBIOSscope = 47, + xFontServer = 48, + xDisplayManager = 49, + dhcpRequestedIPaddr = 50, + dhcpIPaddrLeaseTime = 51, + dhcpOptionOverload = 52, + dhcpMessageType = 53, + dhcpServerIdentifier = 54, + dhcpParamRequest = 55, + dhcpMsg = 56, + dhcpMaxMsgSize = 57, + dhcpT1value = 58, + dhcpT2value = 59, + dhcpClassIdentifier = 60, + dhcpClientIdentifier = 61, + endOption = 255 +}; + +typedef struct dhcpMessage +{ + u_char op; /* message type */ + u_char htype; /* hardware address type */ + u_char hlen; /* hardware address length */ + u_char hops; /* should be zero in client's message */ + u_int xid; /* transaction id */ + u_short secs; /* elapsed time in sec. from trying to boot */ + u_short flags; + u_int ciaddr; /* (previously allocated) client IP address */ + u_int yiaddr; /* 'your' client IP address */ + u_int siaddr; /* should be zero in client's messages */ + u_int giaddr; /* should be zero in client's messages */ + u_char chaddr[16]; /* client's hardware address */ + u_char sname[64]; /* server host name, null terminated string */ + u_char file[128]; /* boot file name, null terminated string */ + u_char options[312]; /* message options */ +} __attribute__((packed)) dhcpMessage; + +struct packed_ether_header +{ + u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ + u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ + u_int16_t ether_type; /* packet type ID field */ +} __attribute__((packed)); + +#define TOKEN_RING_HEADER_PAD sizeof(struct trh_hdr) + sizeof(struct trllc) +typedef struct udpipMessage +{ + struct packed_ether_header ethhdr; + char udpipmsg[IPPACKET_SIZE]; + char pad_for_tokenring_header[TOKEN_RING_HEADER_PAD]; +} __attribute__((packed)) udpipMessage; + +typedef struct dhcpOptions +{ + u_char num; + u_char len[256]; + void *val[256]; +} __attribute__((packed)) dhcpOptions; + + +typedef struct dhcp_interface +{ + char *iface; + int cease; + int running; + int sk; + int foo_sk; + short int saved_if_flags; + int bTokenRing; + unsigned int default_lease_time; + time_t req_sent_time; + struct in_addr default_router; + + int ciaddr; + unsigned char chaddr[ETH_ALEN]; + int siaddr; + unsigned char shaddr[ETH_ALEN]; + unsigned int xid; + unsigned short ip_id; + unsigned char cls_id[DHCP_CLASS_ID_MAX_LEN]; + int cls_id_len; + unsigned char cli_id[DHCP_CLIENT_ID_MAX_LEN]; + int cli_id_len; + dhcpOptions dhcp_options; + + dhcp_client_options *client_options; +} dhcp_interface; + +typedef struct dhcp_option_table +{ + const int option; + const char *name; + const int len; +} dhcp_option_table; + +static dhcp_option_table dhcp_opt_table[] = +{ + { padOption, "padOption", 1 }, + { subnetMask, "subnetMask", 4 }, + { timerOffset, "timerOffset", -1 }, + { routersOnSubnet, "routersOnSubnet", 4 }, + { timeServer, "timeServer", 4 }, + { nameServer, "nameServer", 4 }, + { dns, "dns", 4 }, + { logServer, "logServer", 4 }, + { cookieServer, "cookieServer", 4 }, + { lprServer, "lprServer", 4 }, + { impressServer, "impressServer", 4 }, + { resourceLocationServer,"resourceLocationServer",4 }, + { hostName, "hostName", -1 }, + { bootFileSize, "bootFileSize", 4 }, + { meritDumpFile, "meritDumpFile", 4 }, + { domainName, "domainName", -1 }, + { swapServer, "swapServer", 4 }, + { rootPath, "rootPath", -1 }, + { extentionsPath, "extentionsPath", -1 }, + { IPforwarding, "IPforwarding", -1 }, + { nonLocalSourceRouting, "nonLocalSourceRouting", -1 }, + { policyFilter, "policyFilter", -1 }, + { maxDgramReasmSize, "maxDgramReasmSize", -1 }, + { defaultIPTTL, "defaultIPTTL", -1 }, + { pathMTUagingTimeout, "pathMTUagingTimeout", -1 }, + { pathMTUplateauTable, "pathMTUplateauTable", -1 }, + { ifMTU, "ifMTU", -1 }, + { allSubnetsLocal, "allSubnetsLocal", -1 }, + { broadcastAddr, "broadcastAddr", 4 }, + { performMaskDiscovery, "performMaskDiscovery", -1 }, + { routerSolicitationAddr,"routerSolicitationAddr",-1 }, + { staticRoute, "staticRoute", 4 }, + { trailerEncapsulation, "trailerEncapsulation", -1 }, + { arpCacheTimeout, "arpCacheTimeout", -1 }, + { ethernetEncapsulation, "ethernetEncapsulation", -1 }, + { tcpDefaultTTL, "tcpDefaultTTL", -1 }, + { tcpKeepaliveInterval, "tcpKeepaliveInterval", -1 }, + { tcpKeepaliveGarbage, "tcpKeepaliveGarbage", -1 }, + { nisDomainName, "nisDomainName", -1 }, + { nisServers, "nisServers", 4 }, + { ntpServers, "ntpServers", 4 }, + { vendorSpecificInfo, "vendorSpecificInfo", -1 }, + { netBIOSnameServer, "netBIOSnameServer", -1 }, + { netBIOSdgramDistServer,"netBIOSdgramDistServer",-1 }, + { netBIOSnodeType, "netBIOSnodeType", -1 }, + { netBIOSscope, "netBIOSscope", -1 }, + { xFontServer, "xFontServer", -1 }, + { xDisplayManager, "xDisplayManager", -1 }, + { dhcpRequestedIPaddr, "dhcpRequestedIPaddr", 4 }, + { dhcpIPaddrLeaseTime, "dhcpIPaddrLeaseTime", 4 }, + { dhcpOptionOverload, "dhcpOptionOverload", -1 }, + { dhcpMessageType, "dhcpMessageType", -1 }, + { dhcpServerIdentifier, "dhcpServerIdentifier", -1 }, + { dhcpParamRequest, "dhcpParamRequest", -1 }, + { dhcpMsg, "dhcpMsg", -1 }, + { dhcpMaxMsgSize, "dhcpMaxMsgSize", -1 }, + { dhcpT1value, "dhcpT1value", 4 }, + { dhcpT2value, "dhcpT2value", 4 }, + { dhcpClassIdentifier, "dhcpClassIdentifier", -1 }, + { dhcpClientIdentifier, "dhcpClientIdentifier", -1 }, + { -1, NULL, -1 } +}; + +typedef udpipMessage *(*dhcp_msg_build_proc)(dhcp_interface *); + +int dhcp_reboot(dhcp_interface *iface); +int dhcp_init(dhcp_interface *iface); +int dhcp_request(dhcp_interface *iface, dhcp_msg_build_proc buildDhcpMsg); +int dhcp_renew(dhcp_interface *iface); +int dhcp_rebind(dhcp_interface *iface); +int dhcp_release(dhcp_interface *iface); +#ifdef ARPCHECK +int dhcp_decline(dhcp_interface *iface); +#endif +int dhcp_inform(dhcp_interface *iface); + +#endif diff --git a/dhcpcd/dhcp_test.c b/dhcpcd/dhcp_test.c new file mode 100644 index 0000000000..94519ed01e --- /dev/null +++ b/dhcpcd/dhcp_test.c @@ -0,0 +1,30 @@ +#include "dhcpcd.h" +#include "client.h" +#include +#include + +int main (int argc, char **argv) +{ + dhcp_client_options opts; + dhcp_interface *iface; + + if (argc < 2 || argv[1] == NULL) + { + fprintf (stderr, "Need an interface\n"); + exit (1); + } + + memset (&opts, 0, sizeof (dhcp_client_options)); + opts.base_timeout = 5; + + openlog ("dhcp_test", LOG_CONS | LOG_PERROR, LOG_USER); + + if (!(iface = dhcp_interface_init (argv[1], &opts))) + exit (1); + + dhcp_init (iface); + + dhcp_interface_free (iface); + + exit (0); +} diff --git a/dhcpcd/dhcpcd.c b/dhcpcd/dhcpcd.c new file mode 100644 index 0000000000..01c6086085 --- /dev/null +++ b/dhcpcd/dhcpcd.c @@ -0,0 +1,221 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dhcpcd.h" +#include "client.h" + + +/* + * DHCP Client Daemon v1.3.22-pl4 + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * Location: http://www.phystech.com/download/ + */ + +void classIDsetup(dhcp_interface *iface, const char *g_cls_id); +void clientIDsetup(dhcp_interface *iface, const char *g_cli_id); +void releaseDhcpOptions (dhcp_interface *iface); + +/*****************************************************************************/ +dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *in_opts) +{ + int o = 1; + unsigned i = 0; + struct ifreq ifr; + struct sockaddr_pkt sap; + struct sockaddr_in clientAddr; + dhcp_interface *iface = NULL; + dhcp_client_options *opts = NULL; + + if (!if_name || !in_opts) + return NULL; + + if (!(iface = calloc (1, sizeof (dhcp_interface)))) + return NULL; + iface->iface = strdup (if_name); + iface->default_lease_time = DHCP_DEFAULT_LEASETIME; + iface->xid = random (); + iface->sk = -1; + iface->foo_sk = -1; + + if (!(opts = calloc (1, sizeof (dhcp_client_options)))) + goto err_out; + memcpy (opts, in_opts, sizeof (dhcp_client_options)); + iface->client_options = opts; + + classIDsetup (iface, iface->client_options->class_id); + clientIDsetup (iface, iface->client_options->client_id); + + memset (&ifr, 0, sizeof(struct ifreq)); + memcpy (ifr.ifr_name, iface->iface, strlen (iface->iface)); + iface->sk = socket (AF_PACKET, SOCK_PACKET, htons(ETH_P_ALL)); + if (iface->sk == -1) + { + syslog (LOG_ERR,"dhcp_interface_init: socket: %m\n"); + goto err_out; + } + + if ( ioctl (iface->sk, SIOCGIFHWADDR, &ifr) ) + { + syslog(LOG_ERR,"dhcpStart: ioctl SIOCGIFHWADDR: %m\n"); + goto err_out; + } + + if (setsockopt (iface->sk, SOL_SOCKET, SO_BROADCAST, &o, sizeof(o)) == -1) + { + syslog (LOG_ERR,"dhcp_interface_init: setsockopt: %m\n"); + goto err_out; + } + + if (ioctl (iface->sk, SIOCGIFFLAGS, &ifr)) + { + syslog (LOG_ERR, "dhcp_interface_init: ioctl SIOCGIFFLAGS: %m\n"); + goto err_out; + } + + iface->saved_if_flags = ifr.ifr_flags; + ifr.ifr_flags = iface->saved_if_flags | IFF_UP | IFF_BROADCAST | IFF_NOTRAILERS | IFF_RUNNING; + if (ioctl (iface->sk, SIOCSIFFLAGS, &ifr)) + { + syslog (LOG_ERR,"dhcp_interface_init: ioctl SIOCSIFFLAGS: %m\n"); + goto err_out; + } + + memset (&sap, 0, sizeof(sap)); + sap.spkt_protocol = htons (ETH_P_ALL); + memcpy (sap.spkt_device, iface->iface, strlen (iface->iface)); + sap.spkt_family = AF_PACKET; + if ( bind (iface->sk, (void*)&sap, sizeof(struct sockaddr)) == -1 ) + syslog (LOG_ERR,"dhcp_interface_init: bind: %m\n"); + + memcpy (iface->chaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + fprintf(stdout,"dhcpcd: MAC address = %02x:%02x:%02x:%02x:%02x:%02x\n", + iface->chaddr[0], iface->chaddr[1], iface->chaddr[2], + iface->chaddr[3], iface->chaddr[4], iface->chaddr[5]); + + i = time (NULL) + iface->chaddr[5] + 4*iface->chaddr[4] + 8*iface->chaddr[3] + + 16*iface->chaddr[2] + 32*iface->chaddr[1] + 64*iface->chaddr[0]; + srandom (i); + iface->ip_id = i & 0xffff; + + iface->foo_sk = socket (AF_INET, SOCK_DGRAM, 0); + if ( iface->foo_sk == -1 ) + { + syslog (LOG_ERR,"dhcp_interface_init: socket: %m\n"); + goto err_out; + } + + if (setsockopt (iface->foo_sk, SOL_SOCKET, SO_BROADCAST, &o, sizeof(o))) + syslog (LOG_ERR,"dhcp_interface_init: setsockopt: %m\n"); + memset (&clientAddr.sin_addr, 0, sizeof (&clientAddr.sin_addr)); + clientAddr.sin_family = AF_INET; + clientAddr.sin_port = htons (DHCP_CLIENT_PORT); + if ( bind (iface->foo_sk, (struct sockaddr *)&clientAddr, sizeof(clientAddr)) ) + { + if (errno != EADDRINUSE) + syslog (LOG_ERR,"dhcp_interface_init: bind: %m\n"); + close (iface->foo_sk); + iface->foo_sk = -1; + } + else if (fcntl (iface->foo_sk, F_SETFL, O_NONBLOCK) == -1) + { + syslog (LOG_ERR,"dhcp_interface_init: fcntl: %m\n"); + goto err_out; + } + + return iface; + +err_out: + dhcp_interface_free (iface); + return NULL; +} +/*****************************************************************************/ +void dhcp_interface_free (dhcp_interface *iface) +{ + struct ifreq ifr; + struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); + + releaseDhcpOptions (iface); + + if (iface->foo_sk >= 0) + close (iface->foo_sk); + free (iface->iface); + free (iface->client_options); + free (iface); +} + +/*****************************************************************************/ +void dhcp_interface_cease (dhcp_interface *iface) +{ + if (!iface) + return; + + iface->cease = 1; +} + +/*****************************************************************************/ +int dhcp_interface_dhcp_field_exists (dhcp_interface *iface, int val) +{ + if (!iface) return 0; + + return (!!iface->dhcp_options.len[val]); +} + +/*****************************************************************************/ +void *dhcp_interface_get_dhcp_field (dhcp_interface *iface, int val) +{ + if (!iface) return 0; + + return (iface->dhcp_options.val[val]); +} + +/*****************************************************************************/ +int dhcp_interface_get_dhcp_field_len (dhcp_interface *iface, int val) +{ + if (!iface) return 0; + + return (iface->dhcp_options.len[val]); +} + +/*****************************************************************************/ +int dhcp_individual_value_len (int val) +{ + if (val <= dhcpClientIdentifier) + return (dhcp_opt_table[val].len); + else + return -1; +} + diff --git a/dhcpcd/dhcpcd.h b/dhcpcd/dhcpcd.h new file mode 100644 index 0000000000..4945783e74 --- /dev/null +++ b/dhcpcd/dhcpcd.h @@ -0,0 +1,67 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 DHCPCD_H +#define DHCPCD_H + +#include + +#define DHCP_DEFAULT_TIMEOUT 60 +#define DHCP_DEFAULT_LEASETIME 0xffffffff /* infinite lease time */ +#define DHCP_CLASS_ID_MAX_LEN 48 +#define DHCP_CLIENT_ID_MAX_LEN 48 +#define DHCP_HOSTNAME_MAX_LEN 64 + + +/* Return codes */ +#define RET_DHCP_ERROR 0 +#define RET_DHCP_ADDRESS_IN_USE 1 +#define RET_DHCP_TIMEOUT 2 +#define RET_DHCP_CEASED 3 +#define RET_DHCP_NAK 4 +#define RET_DHCP_SUCCESS 5 +#define RET_DHCP_BOUND 6 + + +typedef struct dhcp_client_options +{ + unsigned char host_name[DHCP_HOSTNAME_MAX_LEN]; + unsigned char class_id[DHCP_CLASS_ID_MAX_LEN]; + unsigned char client_id[DHCP_CLIENT_ID_MAX_LEN]; + int do_rfc1541; + int do_broadcast_response; + time_t base_timeout; + int do_checksum; + int send_second_discover; + int window; +} dhcp_client_options; + +struct dhcp_interface *dhcp_interface_init (const char *if_name, dhcp_client_options *in_opts); +void dhcp_interface_free (struct dhcp_interface *iface); +void dhcp_interface_cease (struct dhcp_interface *iface); + +int dhcp_interface_dhcp_field_exists (struct dhcp_interface *iface, int val); +int dhcp_interface_get_dhcp_field_len (struct dhcp_interface *iface, int val); +void *dhcp_interface_get_dhcp_field (struct dhcp_interface *iface, int val); +int dhcp_individual_value_len (int val); + +#endif diff --git a/dhcpcd/dhcpconfig.c b/dhcpcd/dhcpconfig.c new file mode 100644 index 0000000000..346516ff4b --- /dev/null +++ b/dhcpcd/dhcpconfig.c @@ -0,0 +1,524 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" +#include "client.h" +#include "arp.h" + +extern int SetDHCPDefaultRoutes; +extern int DebugFlag; +extern int SetDomainName; +extern int SetHostName; +extern int ReplResolvConf; +extern int ReplNISConf; +extern int ReplNTPConf; + +int resolv_renamed = 0; +int yp_renamed = 0; +int ntp_renamed = 0; + +/* Note: Legths initialised to negative to allow us to distinguish between "empty" and "not set" */ +char InitialHostName[HOSTNAME_MAX_LEN]; +int InitialHostName_len=-1; +char InitialDomainName[HOSTNAME_MAX_LEN]; +int InitialDomainName_len=-1; + +/*****************************************************************************/ +char *cleanmetas(char *cstr) /* this is to clean single quotes out of DHCP strings */ +{ + register char *c=cstr; + do + if ( *c == 39 ) + *c = ' '; + while ( *c++ ); + return cstr; +} +/*****************************************************************************/ +unsigned long getgenmask(unsigned long ip_in) /* this is to guess genmask form network address */ +{ + unsigned long t,p=ntohl(ip_in); + + if ( IN_CLASSA(p) ) + t= ~IN_CLASSA_NET; + else + { + if ( IN_CLASSB(p) ) + t= ~IN_CLASSB_NET; + else + { + if ( IN_CLASSC(p) ) + t= ~IN_CLASSC_NET; + else + t=0; + } + } + while ( t & p ) + t >>= 1; + + return htonl(~t); +} + +/*****************************************************************************/ +int setResolvConf(dhcp_interface *iface) +{ + FILE *f; + + resolv_renamed = 1 + rename (RESOLV_CONF, ""RESOLV_CONF".sv"); + f = fopen(RESOLV_CONF,"w"); + if ( f ) + { + int i; + #if 0 + if ( iface->dchp_options.len[nisDomainName] ) + fprintf(f,"domain %s\n",(char *)iface->dhcp_options.val[nisDomainName]); + else + if ( iface->dhcp_options.len[domainName] ) + fprintf(f,"domain %s\n",(char *)iface->dhcp_options.val[domainName]); + #endif + + for (i = 0; i < iface->dhcp_options.len[dns]; i += 4) + { + fprintf(f,"nameserver %u.%u.%u.%u\n", + ((unsigned char *)iface->dhcp_options.val[dns])[i], + ((unsigned char *)iface->dhcp_options.val[dns])[i+1], + ((unsigned char *)iface->dhcp_options.val[dns])[i+2], + ((unsigned char *)iface->dhcp_options.val[dns])[i+3]); + } + + #if 0 + if ( iface->dhcp_options.len[nisDomainName] + iface->dhcp_options.len[domainName] ) + { + fprintf (f,"search"); + if ( iface->dhcp_options.len[nisDomainName] ) + fprintf (f," %s",(char *)iface->dhcp_options.val[nisDomainName]); + if ( iface->dhcp_options.len[domainName] ) + fprintf (f," %s",(char *)iface->dhcp_options.val[domainName]); + fprintf (f,"\n"); + } + #else + if ( iface->dhcp_options.len[domainName] ) + fprintf(f,"search %s\n",(char *)iface->dhcp_options.val[domainName]); + #endif + fclose(f); + } + else + syslog(LOG_ERR,"dhcpConfig: fopen: %m\n"); + + /* moved the next section of code from before to after we've created + * resolv.conf. See below for explanation. + * res_init() is normally called from within the first function of the + * resolver which is called. Here, we want resolv.conf to be + * reread. Otherwise, we won't be able to find out about our hostname, + * because the resolver won't notice the change in resolv.conf + */ + (void)res_init(); + return 0; +} + +/*****************************************************************************/ +int setNISConf(dhcp_interface *iface) +{ + FILE *f; + + yp_renamed = 1 + rename (NIS_CONF, ""NIS_CONF".sv"); + f = fopen (NIS_CONF,"w"); + if (f) + { + int i; + char *domain=NULL; + + if ( iface->dhcp_options.len[nisDomainName] ) + domain=(char *)iface->dhcp_options.val[nisDomainName]; + else + domain=(char *)iface->dhcp_options.val[domainName]; + + for ( i = 0; i < iface->dhcp_options.len[nisServers]; i += 4) + { + fprintf( f,"domain %s server %u.%u.%u.%u\n", (domain ? domain : "localdomain"), + ((unsigned char *)iface->dhcp_options.val[nisServers])[i], + ((unsigned char *)iface->dhcp_options.val[nisServers])[i+1], + ((unsigned char *)iface->dhcp_options.val[nisServers])[i+2], + ((unsigned char *)iface->dhcp_options.val[nisServers])[i+3]); + } + if ( !iface->dhcp_options.len[nisServers] ) + fprintf (f, "domain %s broadcast\n", (domain ? domain : "localdomain")); + fclose (f); + } + else + syslog (LOG_ERR, "dhcpConfig: fopen: %m\n"); + + return 0; +} + +/*****************************************************************************/ +int setNTPConf(dhcp_interface *iface) +{ + FILE *f; + + ntp_renamed = 1 + rename (NTP_CONF,""NTP_CONF".sv"); + f = fopen(NTP_CONF,"w"); + if ( f ) + { + int net, mask; + + memcpy (&mask, iface->dhcp_options.val[subnetMask], 4); + net = iface->ciaddr & mask; + + /* Note: Revise drift/log file names and stratum for local clock */ + fprintf(f,"restrict default noquery notrust nomodify\n"); + fprintf(f,"restrict 127.0.0.1\n"); + fprintf(f,"restrict %u.%u.%u.%u mask %u.%u.%u.%u\n", + ((unsigned char *)&net)[0], ((unsigned char *)&net)[1], + ((unsigned char *)&net)[2], ((unsigned char *)&net)[3], + ((unsigned char *)&mask)[0], ((unsigned char *)&mask)[1], + ((unsigned char *)&mask)[2], ((unsigned char *)&mask)[3]); + + if ( iface->dhcp_options.len[ntpServers] >= 4 ) + { + int i; + char addr[4*3+3*1+1]; + + for ( i = 0; i < iface->dhcp_options.len[ntpServers]; i += 4) + { + snprintf(addr,sizeof(addr),"%u.%u.%u.%u", + ((unsigned char *)iface->dhcp_options.val[ntpServers])[i], + ((unsigned char *)iface->dhcp_options.val[ntpServers])[i+1], + ((unsigned char *)iface->dhcp_options.val[ntpServers])[i+2], + ((unsigned char *)iface->dhcp_options.val[ntpServers])[i+3]); + fprintf(f,"restrict %s\nserver %s\n",addr,addr); + } + } + else + { /* No servers found, use local clock */ + fprintf(f, "fudge 127.127.1.0 stratum 3\n"); + fprintf(f, "server 127.127.1.0\n"); + } + fprintf(f, "driftfile /etc/ntp.drift\n"); + fprintf(f, "logfile /var/log/ntp.log\n"); + fclose(f); + } + else + syslog(LOG_ERR,"dhcpConfig: fopen: %m\n"); + return 0; +} + +/*****************************************************************************/ +int setHostName (dhcp_interface *iface) +{ + struct hostent *hp = NULL; + char *dname = NULL; + int dname_len = 0; + + if ( !iface->dhcp_options.len[hostName] ) + { + hp = gethostbyaddr ((char *)&iface->ciaddr, sizeof(iface->ciaddr), AF_INET); + if ( hp ) + { + dname = hp->h_name; + while ( *dname > 32 ) + #if 0 + if ( *dname == '.' ) + break; + else + #endif + dname++; + + dname_len = dname-hp->h_name; + iface->dhcp_options.val[hostName] = (char *)malloc(dname_len+1); + iface->dhcp_options.len[hostName] = dname_len; + memcpy ((char *)iface->dhcp_options.val[hostName], hp->h_name, dname_len); + ((char *)iface->dhcp_options.val[hostName])[dname_len] = 0; + iface->dhcp_options.num++; + } + } + if ( InitialHostName_len < 0 && gethostname(InitialHostName, sizeof(InitialHostName)) == 0 ) + { + InitialHostName_len = strlen(InitialHostName); + if ( DebugFlag ) + fprintf (stdout, "dhcpcd: orig hostname = %s\n", InitialHostName); + } + if ( iface->dhcp_options.len[hostName] ) + { + sethostname (iface->dhcp_options.val[hostName], iface->dhcp_options.len[hostName]); + if ( DebugFlag ) + fprintf(stdout,"dhcpcd: your hostname = %s\n", (char *)iface->dhcp_options.val[hostName]); + } + + return 0; +} + +/*****************************************************************************/ +int setDomainName (dhcp_interface *iface) +{ + struct hostent *hp = NULL; + char *dname = NULL; + int dname_len = 0; + + if ( InitialDomainName_len < 0 && getdomainname(InitialDomainName,sizeof(InitialDomainName)) == 0 ) + { + InitialDomainName_len = strlen(InitialDomainName); + if ( DebugFlag ) + fprintf(stdout,"dhcpcd: orig domainname = %s\n",InitialDomainName); + } +#if 0 + if ( iface->dhcp_options.len[nisDomainName] ) + { + setdomainname (iface->dhcp_options.val[nisDomainName], iface->dhcp_options.len[nisDomainName]); + if ( DebugFlag ) + fprintf(stdout, "dhcpcd: your domainname = %s\n", (char *)iface->dhcp_options.val[nisDomainName]); + } + else + { +#endif + if ( ! iface->dhcp_options.len[domainName] ) + { + hp = gethostbyaddr((char *)&iface->ciaddr, sizeof(iface->ciaddr), AF_INET); + if ( hp ) + { + dname=hp->h_name; + while ( *dname > 32 ) + { + if ( *dname == '.' ) + { + dname++; + break; + } + else + dname++; + } + + dname_len = strlen (dname); + if ( dname_len ) + { + iface->dhcp_options.val[domainName]=(char *)malloc(dname_len+1); + iface->dhcp_options.len[domainName]=dname_len; + memcpy((char *)iface->dhcp_options.val[domainName], dname,dname_len); + ((char *)iface->dhcp_options.val[domainName])[dname_len]=0; + iface->dhcp_options.num++; + } + } + } + + if ( iface->dhcp_options.len[domainName] ) + { + setdomainname(iface->dhcp_options.val[domainName], iface->dhcp_options.len[domainName]); + if ( DebugFlag ) + fprintf(stdout,"dhcpcd: your domainname = %s\n", (char *)iface->dhcp_options.val[domainName]); + } +#if 0 + } +#endif + return 0; +} + +/*****************************************************************************/ +int setDefaultRoute (dhcp_interface *iface, char *route_addr) +{ + struct rtentry rtent; + struct sockaddr_in *p; + + memset (&rtent, 0, sizeof(struct rtentry)); + p = (struct sockaddr_in *)&rtent.rt_dst; + p->sin_family = AF_INET; + p->sin_addr.s_addr = 0; + p = (struct sockaddr_in *)&rtent.rt_gateway; + p->sin_family = AF_INET; + memcpy (&p->sin_addr.s_addr, route_addr, 4); + p = (struct sockaddr_in *)&rtent.rt_genmask; + p->sin_family = AF_INET; + p->sin_addr.s_addr = 0; + rtent.rt_dev = iface->iface; + rtent.rt_metric = 1; + rtent.rt_window = iface->client_options->window; + rtent.rt_flags = RTF_UP | RTF_GATEWAY | ( rtent.rt_window ? RTF_WINDOW : 0); + + if ( ioctl(iface->sk,SIOCADDRT,&rtent) == -1 ) + { + if ( errno == ENETUNREACH ) /* possibly gateway is over the bridge */ + { /* try adding a route to gateway first */ + struct rtentry rtent2; + + memset (&rtent2, 0, sizeof(struct rtentry)); + p = (struct sockaddr_in *)&rtent2.rt_dst; + p->sin_family = AF_INET; + p = (struct sockaddr_in *)&rtent2.rt_gateway; + p->sin_family = AF_INET; + p->sin_addr.s_addr = 0; + memcpy (&p->sin_addr.s_addr, route_addr, 4); + p = (struct sockaddr_in *)&rtent2.rt_genmask; + p->sin_family = AF_INET; + p->sin_addr.s_addr = 0xffffffff; + rtent2.rt_dev = iface->iface; + rtent2.rt_metric = 0; + rtent2.rt_flags = RTF_UP | RTF_HOST; + + if ( ioctl (iface->sk, SIOCADDRT, &rtent2) == 0 ) + { + if ( ioctl (iface->sk, SIOCADDRT, &rtent) == -1 ) + { + syslog(LOG_ERR,"dhcpConfig: ioctl SIOCADDRT: %m\n"); + return -1; + } + } + } + else + { + syslog(LOG_ERR,"dhcpConfig: ioctl SIOCADDRT: %m\n"); + return -1; + } + } + return 0; +} +/*****************************************************************************/ +int dhcpConfig(dhcp_interface *iface) +{ + int i; + struct ifreq ifr; + struct rtentry rtent; + struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); + + /* setting IP address */ + memset (&ifr, 0, sizeof(struct ifreq)); + memcpy (ifr.ifr_name, iface->iface, strlen (iface->iface)); + p->sin_family = AF_INET; + p->sin_addr.s_addr = iface->ciaddr; + if ( ioctl (iface->sk, SIOCSIFADDR, &ifr) == -1 ) + { + syslog(LOG_ERR,"dhcpConfig: ioctl SIOCSIFADDR: %m\n"); + return -1; + } + + /* setting netmask */ + memcpy(&p->sin_addr.s_addr,iface->dhcp_options.val[subnetMask],4); + if ( ioctl(iface->sk,SIOCSIFNETMASK,&ifr) == -1 ) + { + p->sin_addr.s_addr = 0xffffffff; /* try 255.255.255.255 */ + if ( ioctl(iface->sk,SIOCSIFNETMASK,&ifr) == -1 ) + { + syslog(LOG_ERR,"dhcpConfig: ioctl SIOCSIFNETMASK: %m\n"); + return -1; + } + } + + /* setting broadcast address */ + memcpy (&p->sin_addr.s_addr, iface->dhcp_options.val[broadcastAddr], 4); + if ( ioctl(iface->sk,SIOCSIFBRDADDR,&ifr) == -1 ) + syslog(LOG_ERR,"dhcpConfig: ioctl SIOCSIFBRDADDR: %m\n"); + + /* setting static routes */ + for ( i = 0; i < iface->dhcp_options.len[staticRoute]; i += 8) + { + struct sockaddr_in *dstp; + struct sockaddr_in *gwp; + struct sockaddr_in *mskp; + + memset (&rtent,0,sizeof(struct rtentry)); + dstp = (struct sockaddr_in *)&rtent.rt_dst; + dstp->sin_family = AF_INET; + memcpy(&dstp->sin_addr.s_addr,((char *)iface->dhcp_options.val[staticRoute])+i,4); + + gwp = (struct sockaddr_in *)&rtent.rt_gateway; + gwp->sin_family = AF_INET; + memcpy(&gwp->sin_addr.s_addr,((char *)iface->dhcp_options.val[staticRoute])+i+4,4); + + mskp = (struct sockaddr_in *)&rtent.rt_genmask; + mskp->sin_family = AF_INET; + mskp->sin_addr.s_addr = getgenmask (dstp->sin_addr.s_addr); + + rtent.rt_flags = RTF_UP|RTF_GATEWAY; + if ( mskp->sin_addr.s_addr == 0xffffffff ) + rtent.rt_flags |= RTF_HOST; + + rtent.rt_dev = iface->iface; + rtent.rt_metric = 1; + if ( ioctl(iface->sk,SIOCADDRT,&rtent) ) + syslog(LOG_ERR,"dhcpConfig: ioctl SIOCADDRT: %m\n"); + } + + if ( SetDHCPDefaultRoutes ) + { + if ( iface->dhcp_options.len[routersOnSubnet] > 3 ) + for ( i = 0; i < iface->dhcp_options.len[routersOnSubnet]; i += 4) + setDefaultRoute (iface, iface->dhcp_options.val[routersOnSubnet]); + } + else if ( iface->default_router.s_addr > 0 ) + setDefaultRoute (iface, (char *)&(iface->default_router.s_addr)); + + arpInform(iface); + + if ( DebugFlag ) + fprintf(stdout,"dhcpcd: your IP address = %u.%u.%u.%u\n", + ((unsigned char *)&iface->ciaddr)[0], + ((unsigned char *)&iface->ciaddr)[1], + ((unsigned char *)&iface->ciaddr)[2], + ((unsigned char *)&iface->ciaddr)[3]); + + if ( ReplResolvConf ) + setResolvConf (iface); + + if ( ReplNISConf ) + setNISConf (iface); + + if ( ReplNTPConf ) + setNTPConf (iface); + + if ( SetHostName ) + setHostName (iface); + + if ( SetDomainName ) + setDomainName (iface); +#if 0 + if ( iface->ciaddr == previous ip address ) + { + /* execute_on_change("up"); */ + } + else + { + /* IP address has changed */ + /* execute_on_change("new"); */ + } + if ( *(unsigned int *)iface->dhcp_options.val[dhcpIPaddrLeaseTime] == 0xffffffff ) + { + syslog(LOG_INFO,"infinite IP address lease time. Exiting\n"); + /* exit(0); */ + } +#endif + return 0; +} +/*****************************************************************************/ diff --git a/dhcpcd/udpipgen.c b/dhcpcd/udpipgen.c new file mode 100644 index 0000000000..382c8ed65d --- /dev/null +++ b/dhcpcd/udpipgen.c @@ -0,0 +1,119 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 +#include "udpipgen.h" +#include "client.h" + +/*****************************************************************************/ +unsigned short in_cksum(unsigned short *addr, int len) +{ + register int sum = 0; + register u_short *w = addr; + register int nleft = len; + while ( nleft > 1 ) + { + sum += *w++; + nleft -= 2; + } + if ( nleft == 1 ) + { + u_char a = 0; + memcpy(&a,w,1); + sum += a; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return ~sum; +} +/*****************************************************************************/ +void udpipgen (udpiphdr *udpip, unsigned int saddr, unsigned int daddr, unsigned short *ip_id) +{ + /* Use local copy because udpip->ip is not aligned. */ + struct ip ip_local; + struct ip *ip = &ip_local; + struct ipovly *io = (struct ipovly *)udpip->ip; + struct udphdr *udp = (struct udphdr *)udpip->udp; + + io->ih_next = io->ih_prev = 0; + io->ih_x1 = 0; + io->ih_pr = IPPROTO_UDP; + io->ih_len = htons(sizeof(dhcpMessage) + sizeof(struct udphdr)); + io->ih_src.s_addr = saddr; + io->ih_dst.s_addr = daddr; + udp->uh_sport = htons(DHCP_CLIENT_PORT); + udp->uh_dport = htons(DHCP_SERVER_PORT); + udp->uh_ulen = io->ih_len; + udp->uh_sum = 0; + udp->uh_sum = in_cksum((unsigned short *)udpip, sizeof(dhcpMessage) + sizeof(udpiphdr)); + if ( udp->uh_sum == 0 ) + udp->uh_sum = 0xffff; + memcpy(ip,(struct ip *)udpip->ip,sizeof(ip_local)); + ip->ip_hl = 5; + ip->ip_v = IPVERSION; + ip->ip_tos = 0; /* normal service */ + ip->ip_len = htons(sizeof(dhcpMessage) + sizeof(udpiphdr)); + ip->ip_id = htons(*ip_id); *ip_id++; + ip->ip_off = 0; + ip->ip_ttl = IPDEFTTL; /* time to live, 64 by default */ + ip->ip_p = IPPROTO_UDP; + ip->ip_src.s_addr = saddr; + ip->ip_dst.s_addr = daddr; + ip->ip_sum = 0; + memcpy(udpip->ip,ip,sizeof(ip_local)); + ip->ip_sum = in_cksum((unsigned short *)&ip_local,sizeof(struct ip)); + memcpy(udpip->ip,ip,sizeof(ip_local)); +} +/*****************************************************************************/ +int udpipchk(udpiphdr *udpip) +{ + int hl; + struct ip save_ip; + struct ip *ip = (struct ip *)udpip->ip; + struct ipovly *io = (struct ipovly *)udpip->ip; + struct udphdr *udp = (struct udphdr *)udpip->udp; + udpiphdr *nudpip = udpip; + + hl = ip->ip_hl<<2; + if ( in_cksum((unsigned short *)udpip,hl) ) + return -1; + memcpy(&save_ip, udpip->ip, sizeof(struct ip)); + hl -= sizeof(struct ip); + if ( hl ) + { + /* thrash IP options */ + nudpip = (udpiphdr *)((char *)udpip+hl); + memmove((char *)nudpip,udpip,sizeof(struct ip)); + io = (struct ipovly *)nudpip->ip; + ip = (struct ip *)nudpip->ip; + udp = (struct udphdr *)nudpip->udp; + } + if ( udp->uh_sum == 0 ) + return 0; /* no checksum has been done by sender */ + io->ih_next = io->ih_prev = 0; + io->ih_x1 = 0; + io->ih_len = udp->uh_ulen; + hl = ntohs(udp->uh_ulen)+sizeof(struct ip); + if ( in_cksum((unsigned short *)nudpip,hl) ) + return -2; + memcpy(udpip->ip, &save_ip, sizeof(struct ip)); + return 0; +} diff --git a/dhcpcd/udpipgen.h b/dhcpcd/udpipgen.h new file mode 100644 index 0000000000..f1aa13e1fe --- /dev/null +++ b/dhcpcd/udpipgen.h @@ -0,0 +1,58 @@ +/* + * dhcpcd - DHCP client daemon - + * Copyright (C) January, 1998 Sergei Viznyuk + * + * dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon. + * + * This 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 UDPIPGEN_H +#define UDPIPGEN_H + +#include + +#ifndef IPDEFTTL +#define IPDEFTTL 64 +#endif + +struct ipovly +{ + int ih_next,ih_prev; + u_char ih_x1; + u_char ih_pr; + u_short ih_len; + struct in_addr ih_src; + struct in_addr ih_dst; +} __attribute__((packed)); + +struct udphdr +{ + u_int16_t uh_sport; + u_int16_t uh_dport; + u_int16_t uh_ulen; + u_int16_t uh_sum; +} __attribute__((packed)); + +typedef struct udpiphdr +{ + char ip[sizeof(struct ip)]; + char udp[sizeof(struct udphdr)]; +} __attribute__((packed)) udpiphdr; + +void udpipgen (udpiphdr *udpip, unsigned int saddr, unsigned int daddr, unsigned short *ip_id); +int udpipchk (udpiphdr *udpip); + +#endif diff --git a/info-daemon/Makefile.am b/info-daemon/Makefile.am index af595db3a7..de84c73a30 100644 --- a/info-daemon/Makefile.am +++ b/info-daemon/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I${top_srcdir} -CPPFLAGS = \ +AM_CPPFLAGS = \ $(NM_CFLAGS) \ $(GTK_CFLAGS) \ $(GDK_PIXBUF_CFLAGS) \ diff --git a/panel-applet/Makefile.am b/panel-applet/Makefile.am index 320b5c4d9c..3eb1426d39 100644 --- a/panel-applet/Makefile.am +++ b/panel-applet/Makefile.am @@ -5,7 +5,7 @@ NOTIFICATION_ICON_SOURCE=@NOTIFICATION_ICON_SRC@ INCLUDES = -I${top_srcdir} -CPPFLAGS = \ +AM_CPPFLAGS = \ $(NM_CFLAGS) \ $(GLADE_CFLAGS) \ $(DBUS_CFLAGS) \ diff --git a/src/Makefile.am b/src/Makefile.am index 5619a0bc09..ce4995dc55 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,30 +14,33 @@ bin_PROGRAMS = NetworkManager noinst_LTLIBRARIES = libnmbackend.la -NetworkManager_SOURCES = \ - NetworkManagerAP.c \ - NetworkManagerAP.h \ - NetworkManagerAPList.c \ - NetworkManagerAPList.h \ - NetworkManagerDbus.c \ - NetworkManagerDbus.h \ - NetworkManagerDevice.c \ - NetworkManagerDevice.h \ - NetworkManager.c \ - NetworkManagerMain.h \ - NetworkManagerPolicy.c \ - NetworkManagerPolicy.h \ - NetworkManagerUtils.c \ - NetworkManagerUtils.h \ - NetworkManagerWireless.c \ - NetworkManagerWireless.h \ - backends/NetworkManagerSystem.h +NetworkManager_SOURCES = \ + NetworkManagerAP.c \ + NetworkManagerAP.h \ + NetworkManagerAPList.c \ + NetworkManagerAPList.h \ + NetworkManagerDbus.c \ + NetworkManagerDbus.h \ + NetworkManagerDHCP.c \ + NetworkManagerDHCP.h \ + NetworkManagerDevice.c \ + NetworkManagerDevice.h \ + NetworkManager.c \ + NetworkManagerMain.h \ + NetworkManagerPolicy.c \ + NetworkManagerPolicy.h \ + NetworkManagerUtils.c \ + NetworkManagerUtils.h \ + NetworkManagerWireless.c \ + NetworkManagerWireless.h \ + NetworkManagerSystem.c \ + NetworkManagerSystem.h if !WITH_GCRYPT NetworkManager_SOURCES += gnome-keyring-md5.c gnome-keyring-md5.h endif -NetworkManager_LDADD = $(NM_LIBS) $(IWLIB) libnmbackend.la +NetworkManager_LDADD = $(NM_LIBS) $(IWLIB) libnmbackend.la ../dhcpcd/libdhcpc.a if WITH_GCRYPT NetworkManager_LDADD += $(LIBGCRYPT_LIBS) endif diff --git a/src/NetworkManager.c b/src/NetworkManager.c index fd57223ce1..0c26917579 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -40,7 +40,7 @@ #include "NetworkManagerDbus.h" #include "NetworkManagerAP.h" #include "NetworkManagerAPList.h" -#include "backends/NetworkManagerSystem.h" +#include "NetworkManagerSystem.h" /* diff --git a/src/NetworkManagerDHCP.c b/src/NetworkManagerDHCP.c new file mode 100644 index 0000000000..991edaf9bc --- /dev/null +++ b/src/NetworkManagerDHCP.c @@ -0,0 +1,119 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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. + * + * (C) Copyright 2004 Red Hat, Inc. + */ + +#include +#include +#include +#include +#include "NetworkManager.h" +#include "NetworkManagerMain.h" +#include "NetworkManagerDevice.h" +#include "NetworkManagerDHCP.h" +#include "NetworkManagerSystem.h" +#include "../dhcpcd/client.h" + +/* Accessors to device data that only this file should need */ +dhcp_interface *nm_device_get_dhcp_iface (NMDevice *dev); +void nm_device_set_dhcp_iface (NMDevice *dev, dhcp_interface *dhcp_iface); + + +/* + * nm_device_dhcp_run + * + * Start a DHCP transaction on particular device. + * + */ +int nm_device_dhcp_run (NMDevice *dev) +{ + dhcp_interface *dhcp_iface; + dhcp_client_options opts; + int err; + const char *iface; + + g_return_val_if_fail (dev != NULL, RET_DHCP_ERROR); + + memset (&opts, 0, sizeof (dhcp_client_options)); + opts.base_timeout = 25; + + iface = nm_device_get_iface (dev); + if (!(dhcp_iface = dhcp_interface_init (iface, &opts))) + return RET_DHCP_ERROR; + nm_device_set_dhcp_iface (dev, dhcp_iface); + + /* Start off in DHCP INIT state, get a completely new IP address + * and settings. + */ + err = dhcp_init (dhcp_iface); + if (err == RET_DHCP_BOUND) + { + int temp; + + /* Replace basic info */ + nm_system_device_set_ip4_address (dev, dhcp_iface->ciaddr); + + if (dhcp_interface_dhcp_field_exists (dhcp_iface, subnetMask)) + { + memcpy (&temp, dhcp_interface_get_dhcp_field (dhcp_iface, subnetMask), dhcp_individual_value_len (subnetMask)); + nm_system_device_set_ip4_netmask (dev, temp); + } + + if (dhcp_interface_dhcp_field_exists (dhcp_iface, subnetMask)) + { + memcpy (&temp, dhcp_interface_get_dhcp_field (dhcp_iface, broadcastAddr), dhcp_individual_value_len (broadcastAddr)); + nm_system_device_set_ip4_broadcast (dev, temp); + } + + /* Default route */ + if (dhcp_interface_dhcp_field_exists (dhcp_iface, routersOnSubnet)) + { + memcpy (&temp, dhcp_interface_get_dhcp_field (dhcp_iface, routersOnSubnet), dhcp_individual_value_len (routersOnSubnet)); + nm_system_device_set_ip4_default_route (dev, temp); + } + + /* Update /etc/resolv.conf */ + if (dhcp_interface_dhcp_field_exists (dhcp_iface, dns)) + { + nm_system_device_update_resolv_conf (dhcp_interface_get_dhcp_field (dhcp_iface, dns), + dhcp_interface_get_dhcp_field_len (dhcp_iface, dns), dhcp_interface_get_dhcp_field (dhcp_iface, domainName)); + } + } + + dhcp_interface_free (dhcp_iface); + nm_device_set_dhcp_iface (dev, NULL); + + return (err); +} + + +/* + * nm_device_dhcp_cease + * + * Signal dhcp that its supposed to stop and return. + * + */ +void nm_device_dhcp_cease (NMDevice *dev) +{ + g_return_if_fail (dev != NULL); + g_return_if_fail (nm_device_get_dhcp_iface (dev) != NULL); + + dhcp_interface_cease (nm_device_get_dhcp_iface (dev)); +} + diff --git a/src/NetworkManagerDHCP.h b/src/NetworkManagerDHCP.h new file mode 100644 index 0000000000..4a06267975 --- /dev/null +++ b/src/NetworkManagerDHCP.h @@ -0,0 +1,31 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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. + * + * (C) Copyright 2004 Red Hat, Inc. + */ + +#ifndef NETWORK_MANAGER_DHCP_H +#define NETWORK_MANAGER_DHCP_H + +#include "../dhcpcd/dhcpcd.h" + + +int nm_device_dhcp_run (NMDevice *dev); +void nm_device_dhcp_cease (NMDevice *dev); + +#endif diff --git a/src/NetworkManagerDevice.c b/src/NetworkManagerDevice.c index 9f94280e49..9bacea5a1e 100644 --- a/src/NetworkManagerDevice.c +++ b/src/NetworkManagerDevice.c @@ -35,11 +35,13 @@ #include "NetworkManagerWireless.h" #include "NetworkManagerPolicy.h" #include "NetworkManagerAPList.h" -#include "backends/NetworkManagerSystem.h" +#include "NetworkManagerSystem.h" +#include "NetworkManagerDHCP.h" /* Local static prototypes */ static gboolean mii_get_link (NMDevice *dev); static gpointer nm_device_activation_worker (gpointer user_data); +static gboolean nm_device_activation_configure_ip (NMDevice *dev); /******************************************************/ @@ -104,25 +106,27 @@ struct NMDevice { guint refcount; - char *udi; - char *iface; - NMDeviceType type; - NMDriverSupportLevel driver_support_level; + char *udi; + char *iface; + NMDeviceType type; + NMDriverSupportLevel driver_support_level; - gboolean link_active; - guint32 ip4_address; + gboolean link_active; + guint32 ip4_address; /* FIXME: ipv6 address too */ - NMData *app_data; - NMDeviceOptions options; - NMDeviceConfigInfo config_info; + unsigned char hw_addr[ETH_ALEN]; + NMData *app_data; + NMDeviceOptions options; + NMDeviceConfigInfo config_info; + struct dhcp_interface *dhcp_iface; - gboolean activating; /* Set by main thread before beginning activation */ - gboolean just_activated; /* Set by activation thread after successful activation */ - gboolean quit_activation; /* Flag to signal activation thread to stop activating */ - gboolean activation_failed; /* Did the activation fail? */ + gboolean activating; /* Set by main thread before beginning activation */ + gboolean just_activated; /* Set by activation thread after successful activation */ + gboolean quit_activation; /* Flag to signal activation thread to stop activating */ + gboolean activation_failed; /* Did the activation fail? */ - gboolean test_device; - gboolean test_device_up; + gboolean test_device; + gboolean test_device_up; }; /******************************************************/ @@ -352,13 +356,15 @@ NMDevice *nm_device_new (const char *iface, const char *udi, gboolean test_dev, if (nm_device_get_driver_support_level (dev) != NM_DRIVER_UNSUPPORTED) { - /* Grab IP config data for this device from the system configuration files */ - nm_device_update_ip4_address (dev); - nm_system_device_update_config_info (dev); - /* Have to bring the device up before checking link status. */ nm_device_bring_up (dev); nm_device_update_link_active (dev, TRUE); + + nm_device_update_ip4_address (dev); + nm_device_update_hw_address (dev); + + /* Grab IP config data for this device from the system configuration files */ + nm_system_device_update_config_info (dev); } return (dev); @@ -409,6 +415,32 @@ void nm_device_unref (NMDevice *dev) } +/* + * nm_device_open_sock + * + * Get a control socket for network operations. + * + */ +int nm_device_open_sock (void) +{ + int fd; + + /* Try to grab a control socket */ + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd >= 0) + return (fd); + fd = socket(PF_PACKET, SOCK_DGRAM, 0); + if (fd >= 0) + return (fd); + fd = socket(PF_INET6, SOCK_DGRAM, 0); + if (fd >= 0) + return (fd); + + syslog (LOG_ERR, "nm_get_network_control_socket() could not get network control socket."); + return (-1); +} + + /* * Get/set functions for UDI */ @@ -1021,11 +1053,12 @@ void nm_device_update_ip4_address (NMDevice *dev) return; } - socket = nm_get_network_control_socket (); + socket = nm_device_open_sock (); if (socket < 0) return; - strncpy ((char *)(&req.ifr_name), nm_device_get_iface (dev), 16); /* 16 == IF_NAMESIZE */ + memset (&req, 0, sizeof (struct ifreq)); + strncpy ((char *)(&req.ifr_name), nm_device_get_iface (dev), strlen (nm_device_get_iface (dev))); err = ioctl (socket, SIOCGIFADDR, &req); close (socket); if (err != 0) @@ -1056,6 +1089,51 @@ void nm_device_get_ip6_address(NMDevice *dev) } +/* + * nm_device_get_hw_address + * + * Get a device's hardware address + * + */ +void nm_device_get_hw_address(NMDevice *dev, unsigned char hw_addr[ETH_ALEN]) +{ + g_return_if_fail (dev != NULL); + + memcpy (hw_addr, dev->hw_addr, ETH_ALEN); +} + +void nm_device_update_hw_address (NMDevice *dev) +{ + struct ifreq req; + int socket; + int err; + + g_return_if_fail (dev != NULL); + g_return_if_fail (dev->app_data != NULL); + g_return_if_fail (nm_device_get_iface (dev) != NULL); + + /* Test devices get a nice, bogus IP address */ + if (dev->test_device) + { + memset (dev->hw_addr, 0, ETH_ALEN); + return; + } + + socket = nm_device_open_sock (); + if (socket < 0) + return; + + memset (&req, 0, sizeof (struct ifreq)); + strncpy ((char *)(&req.ifr_name), nm_device_get_iface (dev), strlen (nm_device_get_iface (dev))); + err = ioctl (socket, SIOCGIFHWADDR, &req); + close (socket); + if (err != 0) + return; + + memcpy (dev->hw_addr, req.ifr_hwaddr.sa_data, ETH_ALEN); +} + + /* * nm_device_set_up_down * @@ -1081,7 +1159,7 @@ static void nm_device_set_up_down (NMDevice *dev, gboolean up) if (nm_device_get_driver_support_level (dev) == NM_DRIVER_UNSUPPORTED) return; - iface_fd = nm_get_network_control_socket (); + iface_fd = nm_device_open_sock (); if (iface_fd < 0) return; @@ -1138,7 +1216,7 @@ gboolean nm_device_is_up (NMDevice *dev) if (dev->test_device) return (dev->test_device_up); - iface_fd = nm_get_network_control_socket (); + iface_fd = nm_device_open_sock (); if (iface_fd < 0) return (FALSE); @@ -1310,7 +1388,7 @@ static gboolean nm_device_activation_should_cancel (NMDevice *dev) * FALSE on unsuccessful activation (ie no best AP) * */ -static gboolean nm_device_activate_wireless (NMDevice *dev, NMAccessPoint *ap, guint *bad_crypt_packets) +static gboolean nm_device_set_wireless_config (NMDevice *dev, NMAccessPoint *ap, NMDeviceAuthMethod auth) { gboolean success = FALSE; const char *essid = NULL; @@ -1320,8 +1398,6 @@ static gboolean nm_device_activate_wireless (NMDevice *dev, NMAccessPoint *ap, g g_return_val_if_fail (ap != NULL, FALSE); g_return_val_if_fail (nm_ap_get_essid (ap) != NULL, FALSE); - *bad_crypt_packets = 0; - /* Force the card into Managed/Infrastructure mode */ nm_device_set_mode_managed (dev); nm_device_set_essid (dev, " "); @@ -1334,14 +1410,16 @@ static gboolean nm_device_activate_wireless (NMDevice *dev, NMAccessPoint *ap, g if (nm_ap_get_encrypted (ap) && nm_ap_get_enc_key_source (ap)) { char *hashed_key = nm_ap_get_enc_key_hashed (ap); - nm_device_set_enc_key (dev, hashed_key, NM_DEVICE_AUTH_METHOD_SHARED_KEY); + nm_device_set_enc_key (dev, hashed_key, auth); g_free (hashed_key); } nm_device_set_essid (dev, essid); - *bad_crypt_packets = nm_device_get_bad_crypt_packets (dev); - syslog (LOG_INFO, "nm_device_wireless_activate(%s) using essid '%s'", nm_device_get_iface (dev), essid); + syslog (LOG_INFO, "nm_device_wireless_activate(%s) using essid '%s', with %s authentication.", + nm_device_get_iface (dev), essid, (auth == NM_DEVICE_AUTH_METHOD_NONE) ? "no" : + ((auth == NM_DEVICE_AUTH_METHOD_OPEN_SYSTEM) ? "Open System" : + ((auth == NM_DEVICE_AUTH_METHOD_SHARED_KEY) ? "Shared Key" : "unknown"))); /* Bring the device up and pause to allow card to associate */ nm_device_bring_up (dev); @@ -1371,15 +1449,16 @@ gboolean AP_NEED_KEY (NMAccessPoint *ap) return (FALSE); } -gboolean HAVE_LINK (NMDevice *dev, guint32 bad_crypt_packets) +gboolean HAVE_LINK (NMDevice *dev) { g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail (nm_device_is_wireless (dev), FALSE); - syslog (LOG_NOTICE, "HAVELINK: act=%d && (dev_crypt=%d <= prev_crypt=%d)\n", nm_device_get_link_active (dev), nm_device_get_bad_crypt_packets (dev), bad_crypt_packets); - return (nm_device_get_link_active (dev) && (nm_device_get_bad_crypt_packets (dev) <= bad_crypt_packets)); + syslog (LOG_NOTICE, "HAVELINK: act=%d\n", nm_device_get_link_active (dev)); + return (nm_device_get_link_active (dev)); } +#if 0 /* * nm_device_activate_wireless_wait_for_link * @@ -1495,6 +1574,159 @@ out: nm_ap_unref (best_ap); dev->options.wireless.now_scanning = FALSE; } +#endif + +/* + * nm_device_activate_wireless + * + * Activate a wireless ethernet device + * + */ +static gboolean nm_device_activate_wireless (NMDevice *dev) +{ + NMAccessPoint *best_ap; + gboolean success = FALSE; + guint8 attempt = 1; + char last_essid [50] = "\0"; + + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (dev->app_data != NULL, FALSE); + +get_ap: + /* If we were told to quit activation, stop the thread and return */ + if (nm_device_activation_should_cancel (dev)) + goto out; + + /* Get a valid "best" access point we should connect to */ + while (!(best_ap = nm_device_get_best_ap (dev))) + { + dev->options.wireless.now_scanning = TRUE; + syslog (LOG_DEBUG, "nm_device_activate_wireless(%s): waiting for an access point.", nm_device_get_iface (dev)); + g_usleep (G_USEC_PER_SEC * 2); + + /* If we were told to quit activation, stop the thread and return */ + if (nm_device_activation_should_cancel (dev)) + goto out; + } + + if (!nm_ap_get_encrypted (best_ap)) + { + nm_device_set_wireless_config (dev, best_ap, NM_DEVICE_AUTH_METHOD_NONE); + + /* If its unencrypted and we don't have a link, we can't use this AP. + * If we can't get an IP address off this AP, we can't use it either. + */ + if (!HAVE_LINK (dev) || !nm_device_activation_configure_ip (dev)) + { + syslog (LOG_DEBUG, "nm_device_activate_wireless(%s): no link to '%s', or couldn't get configure interface for IP. Trying another access point.", + nm_device_get_iface (dev), nm_ap_get_essid (best_ap) ? nm_ap_get_essid (best_ap) : "(none)"); + nm_ap_set_invalid (best_ap, TRUE); + nm_ap_list_append_ap (dev->app_data->invalid_ap_list, best_ap); + nm_ap_unref (best_ap); + nm_device_update_best_ap (dev); + goto get_ap; + } + success = TRUE; + } + else + { + NMDeviceAuthMethod auth = NM_DEVICE_AUTH_METHOD_SHARED_KEY; + gboolean need_key = AP_NEED_KEY (best_ap); + + need_key: + if (need_key) + { + char *essid = nm_ap_get_essid (best_ap); + if (strcmp (essid, last_essid) != 0) + attempt = 1; + strncpy (&last_essid[0], essid, 49); + + /* Get a wireless key */ + dev->options.wireless.user_key_received = FALSE; + nm_dbus_get_user_key_for_network (dev->app_data->dbus_connection, dev, best_ap, attempt); + attempt++; + need_key = FALSE; + + /* Wait for the key to come back */ + syslog (LOG_DEBUG, "nm_device_activation_worker(%s): asking for user key.", nm_device_get_iface (dev)); + while (!dev->options.wireless.user_key_received && !dev->quit_activation) + g_usleep (G_USEC_PER_SEC / 2); + + syslog (LOG_DEBUG, "nm_device_activation_worker(%s): user key received.", nm_device_get_iface (dev)); + + /* If we were told to quit activation, stop the thread and return */ + if (nm_device_activation_should_cancel (dev)) + { + nm_ap_unref (best_ap); + goto out; + } + + /* User may have cancelled the key request, so we need to update our best AP again. + * However, if they didn't, since there will now be a key, we won't get back here for + * the same access point until the key is deemed incorrect below. + */ + nm_ap_unref (best_ap); + goto get_ap; + } + + while (auth > NM_DEVICE_AUTH_METHOD_NONE) + { + int ip_success = FALSE; + + nm_device_set_wireless_config (dev, best_ap, auth); + if (!HAVE_LINK (dev) && (auth == NM_DEVICE_AUTH_METHOD_SHARED_KEY)) + { + syslog (LOG_DEBUG, "nm_device_activate_wireless(%s): no hardware link to '%s' in Shared Key mode, trying Open System.", + nm_device_get_iface (dev), nm_ap_get_essid (best_ap) ? nm_ap_get_essid (best_ap) : "(none)"); + /* Back down to Open System mode */ + auth--; + continue; + } + else if (!HAVE_LINK (dev)) + { + /* Must be in Open System mode and it still didn't work, so + * we'll invalidate the current "best" ap and get another one */ + syslog (LOG_DEBUG, "nm_device_activate_wireless(%s): no hardware link to '%s' in Open System mode, trying another access point.", + nm_device_get_iface (dev), nm_ap_get_essid (best_ap) ? nm_ap_get_essid (best_ap) : "(none)"); + nm_ap_set_invalid (best_ap, TRUE); + nm_ap_list_append_ap (dev->app_data->invalid_ap_list, best_ap); + nm_ap_unref (best_ap); + nm_device_update_best_ap (dev); + goto get_ap; + } + ip_success = nm_device_activation_configure_ip (dev); + if (!ip_success && (auth == NM_DEVICE_AUTH_METHOD_SHARED_KEY)) + { + /* Back down to Open System mode */ + syslog (LOG_DEBUG, "nm_device_activate_wireless(%s): could not get IP configuration info for '%s' in Shared Key mode, trying Open System.", + nm_device_get_iface (dev), nm_ap_get_essid (best_ap) ? nm_ap_get_essid (best_ap) : "(none)"); + auth--; + continue; + } + else if (!ip_success) + { + /* Open System mode failed, we must have bad WEP key */ + syslog (LOG_DEBUG, "nm_device_activate_wireless(%s): could not get IP configuration info for '%s' in Open System mode, asking for new key.", + nm_device_get_iface (dev), nm_ap_get_essid (best_ap) ? nm_ap_get_essid (best_ap) : "(none)"); + need_key = TRUE; + goto need_key; + } + + /* OK, we have a link and we have IP address info, we're good */ + success = TRUE; + break; + } + } + + if (success) + { + syslog (LOG_DEBUG, "nm_device_activate_wireless(%s): Success! Connected to access point '%s' and got an IP address.", + nm_device_get_iface (dev), nm_ap_get_essid (best_ap) ? nm_ap_get_essid (best_ap) : "(none)"); + } + +out: + return (success); +} /* @@ -1510,22 +1742,18 @@ static gboolean nm_device_activation_configure_ip (NMDevice *dev) g_return_val_if_fail (dev != NULL, FALSE); + nm_system_delete_default_route (); if (nm_device_config_get_use_dhcp (dev)) { - /* FIXME - * Bringing the device up and then down evidentally helps with - * IPv6 for some reason, according to j bootlab org - */ - nm_device_bring_down (dev); - nm_device_bring_up (dev); - if (nm_system_device_run_dhcp (dev)) + int err; + + err = nm_device_dhcp_run (dev); + if (err == RET_DHCP_BOUND) success = TRUE; else { /* Interfaces cannot be down if they are the active interface, * otherwise we cannot use them for scanning or link detection. - * If dhclient doesn't get a DHCP address, it will take the interface - * down, so we reactivate it here. */ if (nm_device_is_wireless (dev)) { @@ -1533,7 +1761,8 @@ static gboolean nm_device_activation_configure_ip (NMDevice *dev) nm_device_set_enc_key (dev, NULL, NM_DEVICE_AUTH_METHOD_NONE); } - nm_device_bring_up (dev); + if (!nm_device_is_up (dev)) + nm_device_bring_up (dev); } } else @@ -1556,88 +1785,42 @@ static gboolean nm_device_activation_configure_ip (NMDevice *dev) static gpointer nm_device_activation_worker (gpointer user_data) { NMDevice *dev = (NMDevice *)user_data; - unsigned char hostname[100] = "\0"; - int host_err; - NMAccessPoint *best_ap = NULL; + gboolean success = FALSE; g_return_val_if_fail (dev != NULL, NULL); g_return_val_if_fail (dev->app_data != NULL, NULL); syslog (LOG_DEBUG, "nm_device_activation_worker (%s) started...", nm_device_get_iface (dev)); - /* If its a wireless device, set the ESSID and WEP key */ + /* Bring the device up */ + if (!nm_device_is_up (dev)); + nm_device_bring_up (dev); + if (nm_device_is_wireless (dev)) - { - nm_device_activate_wireless_wait_for_link (dev); - - /* If we were told to quit activation, stop the thread and return */ - if (nm_device_activation_should_cancel (dev)) - goto out; - - best_ap = nm_device_get_best_ap (dev); - syslog (LOG_DEBUG, "nm_device_activation_worker(%s): using ESSID '%s'", nm_device_get_iface (dev), - best_ap ? nm_ap_get_essid (best_ap) : "none"); - if (best_ap) - nm_ap_unref (best_ap); - } - else - { - /* Bring the device up */ - if (!nm_device_is_up (dev)); - nm_device_bring_up (dev); - } - - nm_system_delete_default_route (); - nm_system_device_stop_dhcp (dev); - - /* If we don't have a "best" ap, don't try to get a DHCP address or restart the name service cache */ - if (nm_device_is_wireless (dev)) - best_ap = nm_device_get_best_ap (dev); - if (nm_device_is_wired (dev) || best_ap) - { - gboolean success; - /* Save machine host name */ - host_err = gethostname (&hostname[0], 100); - - if (!(success = nm_device_activation_configure_ip (dev))) - syslog (LOG_DEBUG, "nm_device_activation_worker(%s): could not retrieve and assign IP information to device\n", nm_device_get_iface (dev)); - - /* Set the hostname back to what it was before so that X11 doesn't - * puke when the hostname changes, and so users can actually launch stuff. - */ - if (host_err >= 0) - sethostname (hostname, strlen (hostname)); - - /* If we were told to quit activation, stop the thread and return */ - if (nm_device_activation_should_cancel (dev)) - goto out; - - if (!success) - { - dev->activating = FALSE; - dev->just_activated = FALSE; - dev->activation_failed = TRUE; - dev->quit_activation = FALSE; - goto out; - } - - /* Make system aware of any new DNS settings from resolv.conf */ - nm_system_update_dns (); - } - if (best_ap) - nm_ap_unref (best_ap); + success = nm_device_activate_wireless (dev); + else if (nm_device_is_wired (dev)) + success = nm_device_activation_configure_ip (dev); /* If we were told to quit activation, stop the thread and return */ if (nm_device_activation_should_cancel (dev)) goto out; - nm_device_update_ip4_address (dev); + if (!success) + { + dev->activating = FALSE; + dev->just_activated = FALSE; + dev->activation_failed = TRUE; + dev->quit_activation = FALSE; + goto out; + } dev->just_activated = TRUE; dev->activating = FALSE; dev->activation_failed = FALSE; dev->quit_activation = FALSE; + nm_device_update_ip4_address (dev); + syslog (LOG_DEBUG, "nm_device_activation_worker(%s): device activated", nm_device_get_iface (dev)); out: @@ -1710,7 +1893,8 @@ void nm_device_activation_cancel (NMDevice *dev) { syslog (LOG_DEBUG, "nm_device_activation_cancel(%s): cancelling...", nm_device_get_iface (dev)); dev->quit_activation = TRUE; - nm_system_kill_all_dhcp_daemons (); /* dhcp daemons will block, so have to kill them to return control */ + if (dev->dhcp_iface) + nm_device_dhcp_cease (dev); /* Spin until cancelled. Possible race conditions or deadlocks here. * The other problem with waiting here is that we hold up dbus traffic @@ -1991,6 +2175,30 @@ gboolean nm_device_is_best_ap_frozen (NMDevice *dev) } +/* + * Accessor for dhcp_interface + * + */ +struct dhcp_interface *nm_device_get_dhcp_iface (NMDevice *dev) +{ + g_return_val_if_fail (dev != NULL, FALSE); + + return (dev->dhcp_iface); +} + +void nm_device_set_dhcp_iface (NMDevice *dev, struct dhcp_interface *dhcp_iface) +{ + g_return_if_fail (dev != NULL); + + /* NOTE: this function should only be used from the activation worker thread + * which will take care of shutting down any active DHCP threads and cleaning + * up the dev->dhcp_iface structure. + */ + + dev->dhcp_iface = dhcp_iface; +} + + /* * nm_device_get_path_for_ap * diff --git a/src/NetworkManagerDevice.h b/src/NetworkManagerDevice.h index c7d545c5cc..3b93e6adcc 100644 --- a/src/NetworkManagerDevice.h +++ b/src/NetworkManagerDevice.h @@ -43,6 +43,8 @@ NMDevice * nm_device_new (const char *iface, const char *udi, gboolean test_ void nm_device_ref (NMDevice *dev); void nm_device_unref (NMDevice *dev); +int nm_device_open_sock (void); + char * nm_device_get_udi (NMDevice *dev); void nm_device_set_udi (NMDevice *dev, const char *udi); @@ -67,6 +69,9 @@ void nm_device_get_ap_address (NMDevice *dev, struct ether_addr *addr); guint32 nm_device_get_ip4_address (NMDevice *dev); void nm_device_update_ip4_address (NMDevice *dev); +void nm_device_get_hw_address (NMDevice *dev, unsigned char hw_addr[ETH_ALEN]); +void nm_device_update_hw_address (NMDevice *dev); + void nm_device_get_ip6_address (NMDevice *dev); gboolean nm_device_get_supports_wireless_scan (NMDevice *dev); diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c new file mode 100644 index 0000000000..17b508201b --- /dev/null +++ b/src/NetworkManagerSystem.c @@ -0,0 +1,256 @@ +/* NetworkManager -- Network link manager + * + * Dan Williams + * + * 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. + * + * Copyright (C) 2004 Red Hat, Inc. + * Copyright (C) 1996 - 1997 Yoichi Hariguchi + * Copyright (C) January, 1998 Sergei Viznyuk + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "NetworkManagerSystem.h" +#include "NetworkManagerDevice.h" + + +static int nm_system_open_sock (void) +{ + int fd; + + /* Try to grab a control socket */ + fd = socket (AF_PACKET, SOCK_PACKET, htons (ETH_P_ALL)); + if (fd >= 0) + return (fd); + + syslog (LOG_ERR, "nm_system_open_sock() could not get network control socket."); + return (-1); +} + + +gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address) +{ + struct ifreq ifr; + const char *iface; + int sk; + gboolean success = FALSE; + struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); + + g_return_val_if_fail (dev != NULL, FALSE); + + iface = nm_device_get_iface (dev); + sk = nm_system_open_sock (); + if (sk < 0) + return FALSE; + + memset (&ifr, 0, sizeof(struct ifreq)); + memcpy (ifr.ifr_name, iface, strlen (iface)); + p->sin_family = AF_INET; + p->sin_addr.s_addr = ip4_address; + if (ioctl (sk, SIOCSIFADDR, &ifr) == -1) + syslog (LOG_ERR,"nm_system_device_set_ip4_address (%s): failed to set IPv4 address!", iface); + else + { + success = TRUE; + fprintf(stderr, "Your IP address = %u.%u.%u.%u\n", + ((unsigned char *)&ip4_address)[0], + ((unsigned char *)&ip4_address)[1], + ((unsigned char *)&ip4_address)[2], + ((unsigned char *)&ip4_address)[3]); + } + + close (sk); + return (success); +} + + +gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask) +{ + struct ifreq ifr; + const char *iface; + int sk; + gboolean success = FALSE; + struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); + + g_return_val_if_fail (dev != NULL, FALSE); + + iface = nm_device_get_iface (dev); + sk = nm_system_open_sock (); + if (sk < 0) + return FALSE; + + memset (&ifr, 0, sizeof(struct ifreq)); + memcpy (ifr.ifr_name, iface, strlen (iface)); + p->sin_family = AF_INET; + p->sin_addr.s_addr = ip4_netmask; + if (ioctl (sk, SIOCSIFNETMASK, &ifr) == -1) + syslog (LOG_ERR,"nm_system_device_set_ip4_netmask (%s): failed to set IPv4 netmask!", iface); + else + success = TRUE; + + close (sk); + return (success); +} + + +gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast) +{ + struct ifreq ifr; + const char *iface; + int sk; + gboolean success = FALSE; + struct sockaddr_in *p = (struct sockaddr_in *)&(ifr.ifr_addr); + + g_return_val_if_fail (dev != NULL, FALSE); + + iface = nm_device_get_iface (dev); + sk = nm_system_open_sock (); + if (sk < 0) + return FALSE; + + memset (&ifr, 0, sizeof(struct ifreq)); + memcpy (ifr.ifr_name, iface, strlen (iface)); + p->sin_family = AF_INET; + p->sin_addr.s_addr = ip4_broadcast; + if (ioctl (sk, SIOCSIFBRDADDR, &ifr) == -1) + syslog (LOG_ERR,"nm_system_device_set_ip4_netmask (%s): failed to set IPv4 netmask!", iface); + else + success = TRUE; + + close (sk); + return (success); +} + + +gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_route) +{ + const char *iface; + int sk; + gboolean success = FALSE; + struct rtentry rtent; + struct sockaddr_in *p; + + g_return_val_if_fail (dev != NULL, FALSE); + + iface = nm_device_get_iface (dev); + sk = nm_system_open_sock (); + if (sk < 0) + return FALSE; + + memset (&rtent, 0, sizeof (struct rtentry)); + p = (struct sockaddr_in *)&rtent.rt_dst; + p->sin_family = AF_INET; + p->sin_addr.s_addr = 0; + p = (struct sockaddr_in *)&rtent.rt_gateway; + p->sin_family = AF_INET; + p->sin_addr.s_addr = ip4_def_route; + p = (struct sockaddr_in *)&rtent.rt_genmask; + p->sin_family = AF_INET; + p->sin_addr.s_addr = 0; + rtent.rt_dev = (char *)iface; + rtent.rt_metric = 1; + rtent.rt_window = 0; + rtent.rt_flags = RTF_UP | RTF_GATEWAY | ( rtent.rt_window ? RTF_WINDOW : 0); + + if ( ioctl (sk, SIOCADDRT, &rtent) == -1 ) + { + if ( errno == ENETUNREACH ) /* possibly gateway is over the bridge */ + { /* try adding a route to gateway first */ + struct rtentry rtent2; + + memset (&rtent2, 0, sizeof(struct rtentry)); + p = (struct sockaddr_in *)&rtent2.rt_dst; + p->sin_family = AF_INET; + p = (struct sockaddr_in *)&rtent2.rt_gateway; + p->sin_family = AF_INET; + p->sin_addr.s_addr = ip4_def_route; + p = (struct sockaddr_in *)&rtent2.rt_genmask; + p->sin_family = AF_INET; + p->sin_addr.s_addr = 0xffffffff; + rtent2.rt_dev = (char *)iface; + rtent2.rt_metric = 0; + rtent2.rt_flags = RTF_UP | RTF_HOST; + + if ( ioctl (sk, SIOCADDRT, &rtent2) == 0 ) + { + if ( ioctl (sk, SIOCADDRT, &rtent) == 0 ) + success = TRUE; + else + syslog (LOG_ERR,"nm_system_device_set_ip4_default_route (%s): failed to set IPv4 default route! errno = %d", iface, errno); + } + } + else + syslog (LOG_ERR,"nm_system_device_set_ip4_default_route (%s): failed to set IPv4 default route! errno = %d", iface, errno); + } + else + success = TRUE; + + close (sk); + return (success); +} + + +/*****************************************************************************/ +gboolean nm_system_device_update_resolv_conf (void *data, int len, const char *domain_name) +{ + FILE *f; + + g_return_val_if_fail (data != NULL, FALSE); + + if ((f = fopen ("/etc/resolv.conf", "w"))) + { + int i; + + fprintf (f, "; generated by NetworkManager\n"); + + if (domain_name) + fprintf (f, "search %s\n", (char *)domain_name); + + for (i = 0; i < len; i += 4) + { + fprintf (f,"nameserver %u.%u.%u.%u\n", + ((unsigned char *)data)[i], + ((unsigned char *)data)[i+1], + ((unsigned char *)data)[i+2], + ((unsigned char *)data)[i+3]); + } + + fclose(f); + } + else + syslog (LOG_ERR,"nm_system_device_update_resolv_conf(): could not open /etc/resolv.conf\n"); + + /* Reload DNS info for all apps */ + (void)res_init(); + return 0; +} diff --git a/src/backends/NetworkManagerSystem.h b/src/NetworkManagerSystem.h similarity index 72% rename from src/backends/NetworkManagerSystem.h rename to src/NetworkManagerSystem.h index 6b85b1d641..2e0930d45e 100644 --- a/src/backends/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -26,31 +26,29 @@ #include "NetworkManagerDevice.h" -/* Prototypes for system/distribution dependent functions */ +/* Prototypes for system/distribution dependent functions, + * implemented in the backend files in backends/ directory + */ void nm_system_init (void); - gboolean nm_system_device_run_dhcp (NMDevice *dev); - void nm_system_device_stop_dhcp (NMDevice *dev); - gboolean nm_system_device_has_active_routes (NMDevice *dev); void nm_system_device_flush_routes (NMDevice *dev); - void nm_system_device_flush_addresses (NMDevice *dev); - void nm_system_device_update_config_info (NMDevice *dev); - gboolean nm_system_device_setup_static_ip4_config (NMDevice *dev); - void nm_system_enable_loopback (void); - void nm_system_delete_default_route (void); - void nm_system_kill_all_dhcp_daemons (void); - void nm_system_update_dns (void); - void nm_system_load_device_modules (void); +/* Prototyps for system-layer network functions (ie setting IP address, etc) */ +gboolean nm_system_device_set_ip4_address (NMDevice *dev, int ip4_address); +gboolean nm_system_device_set_ip4_netmask (NMDevice *dev, int ip4_netmask); +gboolean nm_system_device_set_ip4_broadcast (NMDevice *dev, int ip4_broadcast); +gboolean nm_system_device_set_ip4_default_route (NMDevice *dev, int ip4_def_route); +gboolean nm_system_device_update_resolv_conf (void *data, int len, const char *domain_name); + #endif diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 686e2172b5..28954fce27 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -104,32 +104,6 @@ int nm_null_safe_strcmp (const char *s1, const char *s2) -/* - * nm_get_network_control_socket - * - * Get a control socket for network operations. - * - */ -int nm_get_network_control_socket (void) -{ - int fd; - - /* Try to grab a control socket */ - fd = socket(PF_INET, SOCK_DGRAM, 0); - if (fd >= 0) - return (fd); - fd = socket(PF_PACKET, SOCK_DGRAM, 0); - if (fd >= 0) - return (fd); - fd = socket(PF_INET6, SOCK_DGRAM, 0); - if (fd >= 0) - return (fd); - - syslog (LOG_ERR, "nm_get_network_control_socket() could not get network control socket."); - return (-1); -} - - /* * nm_ethernet_address_is_valid * diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 2a82083060..4504aaf8bf 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -38,8 +38,6 @@ void nm_unlock_mutex (GMutex *mutex, const char *func); int nm_null_safe_strcmp (const char *s1, const char *s2); -int nm_get_network_control_socket (void); - gboolean nm_ethernet_address_is_valid (struct ether_addr *test_addr); void nm_dispose_scan_results (wireless_scan *result_list); diff --git a/test/Makefile.am b/test/Makefile.am index 28ae6dc729..be95e8f3b3 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,6 @@ INCLUDES = -I${top_srcdir} -CPPFLAGS = \ +AM_CPPFLAGS = \ $(NM_CFLAGS) \ -DDBUS_API_SUBJECT_TO_CHANGE \ -DBINDIR=\"$(bindir)\" \