From 75c08e079aaf8bc8aed01b23ea2b50766ff3251b Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Wed, 26 Jul 2023 22:15:30 -0400 Subject: [PATCH] Import rarpd from iputils-20211215 Well, with rarpd removed from iputils, let's extract it to a standalone package. This is just the bare minimum to start, all source files are unmodified from the iputils-20211215 release, and a brand-new skeleton build system is implemented to compile the software and documentation. --- .gitignore | 14 + COPYING | 339 ++++++++++++++++++++ ChangeLog | 341 +++++++++++++++++++++ Makefile.am | 38 +++ README.md | 34 +++ configure.ac | 41 +++ doc/.gitignore | 1 + doc/custom-man.xsl | 46 +++ doc/rarpd.xml | 184 +++++++++++ m4/.gitignore | 0 src/iputils_common.c | 140 +++++++++ src/iputils_common.h | 73 +++++ src/rarpd.c | 712 +++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 1963 insertions(+) create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100644 README.md create mode 100644 configure.ac create mode 100644 doc/.gitignore create mode 100644 doc/custom-man.xsl create mode 100644 doc/rarpd.xml create mode 100644 m4/.gitignore create mode 100644 src/iputils_common.c create mode 100644 src/iputils_common.h create mode 100644 src/rarpd.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b5eaac7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.o +.deps +.dirstamp +/aclocal.m4 +/autom4te.cache +/compile +/config.* +/configure +/depcomp +/install-sh +/missing +/rarpd +Makefile +Makefile.in diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e2db6c3 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,341 @@ +2020-08-29 Nuno Silva + + common: fix infinite loop when getrandom fails + + Fixes: https://github.com/iputils/iputils/issues/291 + +2020-01-06 Sami Kerola + + common: flush streams before closing them + + On loaded systems slow tty can give false positive exit failure due pending + bytes. Flush the streams that hopefully makes these problems less likely. + + Reference: https://github.com/iputils/iputils/commit/4655ecc5105c383669ef529f21f3344f99e7372f#commitcomment-36628770 + +2019-11-24 Sami Kerola + + rdisc / ninfod: fix format string warning + + warning: format string is not a string literal [-Wformat-nonliteral] + + The above was reported for rdisc.c lines 210 and 212, and ninfod/ninfod.c + lines 162 and 165. + + Reviewed-by: Petr Vorel + +2019-10-31 Philipp Kammerer + + doc: Proofreading rarpd.xml + + A few suggestions to make the manpage more easy to read + +2019-10-17 Maciej Żenczykowski + + iputils_common.h: fix missing #include + + This fixes: + In file included from ping/ping6_common.c:61: + iputils_common.h:63:32: error: declaration of 'struct timespec' will not be visible outside of this function [-Werror,-Wvisibility] + extern void timespecsub(struct timespec *a, struct timespec *b, + ^ + + Change-Id: Icc30a25c30fc606f46def07704cdc6997018d58f + +2019-09-10 Sami Kerola + + ninfod: retire gettimeofday() in favor of clock_gettime() + + Apply to ninfod similar fix as da9a6105b2cab2f92135a282d00cc939760e64c0. + + Discussion about this and the next change spanned over several pull + requests that are mentioned below. + + Reference: https://github.com/iputils/iputils/pull/213 + Reference: https://github.com/iputils/iputils/pull/214 + Reference; https://github.com/iputils/iputils/pull/215 + Acked-by: Petr Vorel + +2019-09-10 Sami Kerola + + common: make seeding pseudo-random number generator easy + + Unify how srand() calls are done, with some care to try avoiding bad + seeding with hope pseudo-random numbers are unpredictable. + + Acked-by: Petr Vorel + +2019-06-10 Petr Vorel + + common: move various fallback definitions into iputils_common.h + +2019-03-25 Jan Tojnar + + doc: Use namespace correctly + + The files declared xmlns:db but did not use the db namespace at all. + They did not define the default namespace at all, which coincidentally + worked with Docbook 4 stylesheets, making them think the files were + written in Docbook 4. + + I fixed the namespaces of the documents and switched to the correct + Docbook 5 stylesheets. + +2019-03-23 Sami Kerola + + common: use single ARRAY_SIZE definition across files + + The ARRAY_SIZE is Rusty Russell’s version, that looks a bit more complicated + than the original, but there is a reason to that. This macro will ensure + macro is used properly, and fail compilation if it is not. See reference + link for further explanation. + + Reference: http://zubplot.blogspot.com/2015/01/gcc-is-wonderful-better-arraysize-macro.html + +2019-03-09 Sami Kerola + + documentation: fix various spelling typos + + Foudn with codespell. + + Reference: https://github.com/codespell-project/codespell + +2019-02-03 Sami Kerola + + libcommon: add string to a number conversion function + + Based on standard libc strtol(), but has convenience wrapping to catch + errors so that one can convert numbers with just a single function call. + +2019-02-02 Sami Kerola + + clang scan-build: fix various build warning + + arping: fix dereference of null pointer. + clockdiff: fix assigned value is garbage or undefined warnings. + ninfod: fix dead assignment and use of uninitialized argument value. + ping: fix dead assignment. + rarpd: fix uninitialized argument value. + rdisc: fix uninitialized argument value. + tracepath: fix dereference of null pointer. + +2019-01-01 Sami Kerola + + rarpd: use libc function to run in the background + + ninfod: check writing a pid file was successful + +2019-01-01 Sami Kerola + + libcommon: check standard streams status at exit + + Earlier commands happily successed when writing to standard out or error did + not work. Following demonstrates old and new behavior of all commands in + this project. + + $ ping -c 1 127.0.0.1 > /dev/full ; echo $? + 0 + $ ping -c 1 127.0.0.1 > /dev/full ; echo $? + ./builddir/ping: write error: No space left on device + 1 + +2018-12-22 Sami Kerola + + rarpd: use error() to report command errors + +2018-12-22 Sami Kerola + + common: move error() portability go-around to common library + + This allows use of error() in other programs. The static common library can + also be used for other utility functions in future. + +2018-12-20 Sami Kerola + + man: reindent xml files + + Due to great amount of change in this update normal review is not possible. + I used following to ensure there are no unexpected changes. + + # Generate old manual pages. + git checkout origin/master + make clean && make + mkdir a + for i in builddir/doc/*; do man $i > a/${i##*/}; done + # Generate new manual pages. + git checkout + make clean && make + mkdir b + for i in builddir/doc/*; do man $i > b/${i##*/}; done + # Compare. + diff -ruP a b + +2018-12-20 Sami Kerola + + man: update to docbook 5 + +2018-12-20 Sami Kerola + + man: fix rarpd command name in synopsis + + While going through this manual page I noticed --help output being + incomplete, so lets sort that out in same go. + +2018-12-18 Sami Kerola + + localization: move nls headers to iputils_common.h + + Aboid boilerplating. + +2018-10-03 Sami Kerola + + warnings: fix multiple errno printing format specifier issues + + All of these report same warning: + ISO C does not support the ‘%m’ gnu_printf format [-Wformat=] + +2018-10-03 Sami Kerola + + add version print out to remaining commands + + For some reason version print out was not implemented in all commands. This + fixes that. + +2018-10-03 Sami Kerola + + ping, rarpd, rdisc: remove historical no-op SA_INTERRUPT + + The sigaction option SA_INTERRUPT has been no-op for long time. + + Reference: https://lwn.net/Articles/229673/ + +2018-10-03 Sami Kerola + + usage: unify usage outputs, and improve their helpfulness + + Just listing options, like ping(8) did, does not help users. + +2018-10-03 Sami Kerola + + various: do not use kernel data types in userspace + + It is long standing recommendation not to mix kernel and user space headers. + See reference for details. + + Reference: https://lwn.net/Articles/113349/ + +2018-10-03 Sami Kerola + + docs: fix docbook xml expectations warnings + + This version of xslproc: + + $ xsltproc --version + Using libxml 20907, libxslt 10132-GITv1.1.32-3-g32c88216 and libexslt 820 + xsltproc was compiled against libxml 20906, libxslt 10132 and libexslt 820 + libxslt 10132 was compiled against libxml 20906 + libexslt 820 was compiled against libxml 20906 + + Printed following warning at each manual page creation. + + [17/25] Generating arping.8 with a custom command. + Note: meta source : no *info/productname or alternative arping + Note: meta source : see http://www.docbook.org/tdg5/en/html/produ arping + Note: meta source : no refentry/refmeta/refmiscinfo@class=source arping + Note: meta source : see http://www.docbook.org/tdg5/en/html/refmi arping + Note: meta version: no *info/productnumber or alternative arping + Note: meta version: see http://www.docbook.org/tdg5/en/html/produ arping + Note: meta version: no refentry/refmeta/refmiscinfo@class=version arping + Note: meta version: see http://www.docbook.org/tdg5/en/html/refmi arping + Warn: meta source : using "iputils" for "source" arping + +2018-10-03 Sami Kerola + + warnings: fix multiple unused parameter warnings + + This fixes multiple instances of unnused parameter warnings, that look like: + ping.c:1025:36: warning: unused parameter 'len' [-Wunused-parameter] + +2018-10-03 Sami Kerola + + warnings: fix multiple signed and unsigned integer expressions + + This fixes many many instances of the following warnings. + + warning: comparison between signed and unsigned integer expressions + [-Wsign-compare] + + Unfortunately the fix includes lots of type casts. Each of them was + considered from overflow point of view, and will hopefully not cause any + issues. + +2018-10-03 Sami Kerola + + warnings: fix rarpd variable initialisation + + Refer struct field names in initialiser, and trust compilers to be standard + compliant and fill rest of the data with zeros. This fixes following + compiler warning: + + rarpd.c:307:4: warning: missing initializer for field 'lladdr' of 'struct + rarp_map' [-Wmissing-field-initializers] + +2018-10-03 Sami Kerola + + warnings: add marker to implicit fallthrough + + This fixes an implicit fallthrough warning, that looks like: + rarpd.c:483:41: warning: this statement may fall through [-Wimplicit-fallthrough=] + +2018-10-03 Sami Kerola + + warnings: remove variable shadowing + + This fixes multiple instances of variable shadowing warning, that look like: + warning: declaration of 'var' shadows a previous local [-Wshadow] + +2017-08-05 David Heidelberg + + doc: convert from converting SGML to XML + + This work is mostly inspired by systemd manpages procedure creation. [1] + + With this commit, you can freely throw SGML tools and you should be fine + with xsltproc :) + + Enjoy! + + Also, please don't be shy fix bugs, it will need more polishing! + + [1] https://github.com/systemd/systemd/tree/master/man + + Fixes bug: https://github.com/iputils/iputils/issues/1 + Fixes bug: https://github.com/iputils/iputils/issues/27 + +2014-04-18 David Heidelberger + + replace non-POSIX compilant caddr_t with char * + + fix include paths, now compile with both glibc and musl + +2012-01-09 YOSHIFUJI Hideaki + + rarpd: Check return value of chdir(). + +2007-10-12 YOSHIFUJI Hideaki + + [RARPD]: Fixed several signedness issues for char strings. + +2007-04-04 YOSHIFUJI Hideaki + + Fix white space errors. + +2006-12-20 Mike Frysinger + + [PATCH] Use socklen_t in all the right places. + +2006-04-16 YOSHIFUJI Hideaki + + Initial import of iputils + + Obtained from . diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..1367d07 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,38 @@ +# Copyright © 2023 Nick Bowler +# +# License WTFPL2: Do What The Fuck You Want To Public License, version 2. +# This is free software: you are free to do what the fuck you want to. +# There is NO WARRANTY, to the extent permitted by law. + +ACLOCAL_AMFLAGS = -I m4 + +AM_CPPFLAGS = -DIPUTILS_VERSION='PACKAGE_STRING,' + +XSLTPROC_MAN = $(XSLTPROC) -o $@ --nonet \ + --stringparam man.output.quietly 1 \ + --stringparam funcsynopsis.style ansi \ + --stringparam man.th.extra1.suppress 1 \ + --stringparam iputils.version 'rarpd' \ + $(XSLTPROCFLAGS) $(srcdir)/doc/custom-man.xsl + +DEV_TOOL_ERROR = { \ + echo "ERROR: *** $$tool is missing on your system."; \ + echo " *** Because of this, I cannot compile $$toolsrc, but"; \ + echo " *** (perhaps because you modified it) the sources appear out"; \ + echo " *** of date. If $$tool is installed but was not detected by"; \ + echo " *** configure, consired setting $$toolvar and re-running configure."; \ + echo " *** See config.log for more details."; } >&2; false + +dist_man_MANS = doc/rarpd.8 +.xml.8: +if !HAVE_XSLTPROC + $(AM_V_GEN)tool=xsltproc toolvar=XSLTPROC toolsrc=$<; \ + $(DEV_TOOL_ERROR) +endif + $(AM_V_GEN) $(XSLTPROC_MAN) $< +$(dist_man_MANS): $(srcdir)/doc/custom-man.xsl +MAINTAINERCLEANFILES = $(dist_man_MANS) +EXTRA_DIST = $(dist_man_MANS:.8=.xml) $(srcdir)/doc/custom-man.xsl + +sbin_PROGRAMS = rarpd +rarpd_SOURCES = src/rarpd.c src/iputils_common.c src/iputils_common.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..9f452b2 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +Reverse-ARP (RARP) is a largely-obsolete protocol for autoconfiguring IPv4 +hosts on a local network. For environments that still need it (e.g., to +netboot older Sun workstations), rarpd-dx is a simple server which responds +to RARP requests. + +This version was originally written by Alexey Kuznetsov and subsequently +maintained by several others. It is extracted from the iputils-20211215 +release into a standalone package with its own standalone build system, +as the utility has been removed from newer versions of iputils. + +# Prerequisites + +Rarpd-dx is written in C, so a working C compiler is required. Its +functionality depends on the Linux-specific packet socket functionality, +and probably does not work on non-Linux hosts. + +# Contributing + +Please send suggestions, bug reports, patches or any other +correspondence regarding rarpd-dx by electronic mail to +[Nick Bowler \][email]. + +[email]: mailto:nbowler@draconx.ca + +# License + +Rarpd-dx is free software: you can redistribute 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. + +{::comment} +Copyright © 2023 Nick Bowler +{:/comment} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..af8b33f --- /dev/null +++ b/configure.ac @@ -0,0 +1,41 @@ +dnl Copyright © 2023 Nick Bowler +dnl +dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2. +dnl This is free software: you are free to do what the fuck you want to. +dnl There is NO WARRANTY, to the extent permitted by law. + +AC_PREREQ([2.68]) +AC_INIT([rarpd], [1], [nbowler@draconx.ca], [rarpd-dx]) + +AM_INIT_AUTOMAKE([-Wall -Wno-portability foreign subdir-objects]) +AM_SILENT_RULES([yes]) + +AC_PROG_CC + +AC_CHECK_PROGS([XSLTPROC], [xsltproc], [not found]) +AS_IF([test x"$XSLTPROC" != x"not found"], + [AC_CACHE_CHECK([whether $XSLTPROC works], [dx_cv_xsltproc_works], +[dx_cv_xsltproc_works=no +cat >conftest.xsl <<'EOF' + + + + +hello + +EOF +cat >conftest.xml <<'EOF' + + +EOF +$XSLTPROC --nonet conftest.xsl conftest.xml >conftest.out 2>&AS_MESSAGE_LOG_FD && + { read var + + + + + + + + + + + + + + + + .TH " + + + + + + " " + + " "" "iputils + + " " + + " + + + + + + + + + " + + " + + + diff --git a/doc/rarpd.xml b/doc/rarpd.xml new file mode 100644 index 0000000..fe45e2a --- /dev/null +++ b/doc/rarpd.xml @@ -0,0 +1,184 @@ + + + + rarpd + iputils + + + + + rarpd + + 8 + iputils + + + + rarpd + answer RARP REQUESTs + + + + + rarpd + + + + + + + interface + + + + + + DESCRIPTION + + Listens for RARP requests broadcasted by clients. If the MAC address + of the client is found in /etc/ethers and the obtained + hostname is resolvable to a valid IP address from the attached network, + rarpd answers to the client with a RARPD reply + and provides an IP address. + + To allow multiple boot servers on the network + rarpd optionally checks if a Sun-like + bootable image in the TFTP directory is present. It should be formatted like + Hexadecimal_IP.ARCH. For example: To + load sparc 193.233.7.98, + C1E90762.SUN4M is linked to an + image appropriate for SUN4M in the directory + /etc/tftpboot. + + + + + WARNING + + This facility is deeply obsoleted by BOOTP and later DHCP + protocols. However, some clients actually still need this to + boot. + + + + + OPTIONS + + + + + + + + Listen on all available interfaces. Currently it is an + internal option, its function is overwritten with the + interface argument. It + should not be used. + + + + + + + + Listen not only to RARP but also ARP messages. Some + rare clients use ARP for some unknown reason. + + + + + + + + Be verbose. + + + + + + + + Debug mode. Do not go to background. + + + + + + + + Do not check for the presence of a boot image. Reply if + MAC address resolves to a valid IP address using + /etc/ethers database and DNS. + + + + + + bootdir + + + TFTP boot directory. Default is + /etc/tftpboot + + + + + + + + Print version and exit. + + + + + + + + SEE ALSO + + + + arping + 8 + , + + tftpd + 8 + . + + + + + AUTHOR + + + rarpd was written by Alexey Kuznetsov + <kuznet@ms2.inr.ac.ru>. + + + + + SECURITY + + + rarpd requires CAP_NET_RAW capability to + listen and send RARP and ARP packets. It also needs + CAP_NET_ADMIN to assist the kernel with ARP resolution; this + is not strictly required, but some (to be more exact: most) of + the clients are so badly broken that they are not able to answer + to ARP before they are fully booted. This is no surprise, taking + into account that clients using RARPD in 2002 are all + unsupported relic creatures of the 90's and even earlier. + + + + + AVAILABILITY + + + rarpd is part of the + iputils package. + + diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/src/iputils_common.c b/src/iputils_common.c new file mode 100644 index 0000000..c41f201 --- /dev/null +++ b/src/iputils_common.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_GETRANDOM +# include +#endif + +#ifdef HAVE_ERROR_H +# include +#else +void error(int status, int errnum, const char *format, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", program_invocation_short_name); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + if (errnum) + fprintf(stderr, ": %s\n", strerror(errnum)); + else + fprintf(stderr, "\n"); + if (status) + exit(status); +} +#endif + +int close_stream(FILE *stream) +{ + const int flush_status = fflush(stream); +#ifdef HAVE___FPENDING + const int some_pending = (__fpending(stream) != 0); +#endif + const int prev_fail = (ferror(stream) != 0); + const int fclose_fail = (fclose(stream) != 0); + + if (flush_status || + prev_fail || (fclose_fail && ( +#ifdef HAVE___FPENDING + some_pending || +#endif + errno != EBADF))) { + if (!fclose_fail && !(errno == EPIPE)) + errno = 0; + return EOF; + } + return 0; +} + +void close_stdout(void) +{ + if (close_stream(stdout) != 0 && !(errno == EPIPE)) { + if (errno) + error(0, errno, "write error"); + else + error(0, 0, "write error"); + _exit(EXIT_FAILURE); + } + if (close_stream(stderr) != 0) + _exit(EXIT_FAILURE); +} + +long strtol_or_err(char const *const str, char const *const errmesg, + const long min, const long max) +{ + long num; + char *end = NULL; + + errno = 0; + if (str == NULL || *str == '\0') + goto err; + num = strtol(str, &end, 10); + if (errno || str == end || (end && *end)) + goto err; + if (num < min || max < num) + error(EXIT_FAILURE, 0, "%s: '%s': out of range: %lu <= value <= %lu", + errmesg, str, min, max); + return num; + err: + error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str); + abort(); +} + +static unsigned int iputil_srand_fallback(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_REALTIME, &ts); + return ((getpid() << 16) ^ getuid() ^ ts.tv_sec ^ ts.tv_nsec); +} + +void iputils_srand(void) +{ + unsigned int i; + +#if HAVE_GETRANDOM + ssize_t ret; + + do { + errno = 0; + ret = getrandom(&i, sizeof(i), GRND_NONBLOCK); + switch (errno) { + case 0: + break; + case EINTR: + continue; + default: + i = iputil_srand_fallback(); + goto done; + } + } while (ret != sizeof(i)); + done: +#else + i = iputil_srand_fallback(); +#endif + srand(i); + /* Consume up to 31 random numbers */ + i = rand() & 0x1F; + while (0 < i) { + rand(); + i--; + } +} + +void timespecsub(struct timespec *a, struct timespec *b, struct timespec *res) +{ + res->tv_sec = a->tv_sec - b->tv_sec; + res->tv_nsec = a->tv_nsec - b->tv_nsec; + + if (res->tv_nsec < 0) { + res->tv_sec--; + res->tv_nsec += 1000000000L; + } +} diff --git a/src/iputils_common.h b/src/iputils_common.h new file mode 100644 index 0000000..26e8f7c --- /dev/null +++ b/src/iputils_common.h @@ -0,0 +1,73 @@ +#ifndef IPUTILS_COMMON_H +#define IPUTILS_COMMON_H + +#include +#include + +#define ARRAY_SIZE(arr) \ + (sizeof(arr) / sizeof((arr)[0]) + \ + sizeof(__typeof__(int[1 - 2 * \ + !!__builtin_types_compatible_p(__typeof__(arr), \ + __typeof__(&arr[0]))])) * 0) + +#ifdef __GNUC__ +# define iputils_attribute_format(t, n, m) __attribute__((__format__ (t, n, m))) +#else +# define iputils_attribute_format(t, n, m) +#endif + +#if defined(USE_IDN) || defined(ENABLE_NLS) +# include +#endif + +#ifdef ENABLE_NLS +# include +# define _(Text) gettext (Text) +#else +# undef bindtextdomain +# define bindtextdomain(Domain, Directory) /* empty */ +# undef textdomain +# define textdomain(Domain) /* empty */ +# define _(Text) Text +#endif + +#ifdef USE_IDN +# include + +# include +# ifndef AI_IDN +# define AI_IDN 0x0040 +# endif +# ifndef AI_CANONIDN +# define AI_CANONIDN 0x0080 +# endif +# ifndef NI_IDN +# define NI_IDN 32 +# endif +#endif /* #ifdef USE_IDN */ + +#ifndef SOL_IPV6 +# define SOL_IPV6 IPPROTO_IPV6 +#endif +#ifndef IP_PMTUDISC_DO +# define IP_PMTUDISC_DO 2 +#endif +#ifndef IPV6_PMTUDISC_DO +# define IPV6_PMTUDISC_DO 2 +#endif + +#ifdef HAVE_ERROR_H +# include +#else +extern void error(int status, int errnum, const char *format, ...); +#endif + +extern int close_stream(FILE *stream); +extern void close_stdout(void); +extern long strtol_or_err(char const *const str, char const *const errmesg, + const long min, const long max); +extern void iputils_srand(void); +extern void timespecsub(struct timespec *a, struct timespec *b, + struct timespec *res); + +#endif /* IPUTILS_COMMON_H */ diff --git a/src/rarpd.c b/src/rarpd.c new file mode 100644 index 0000000..21cf99a --- /dev/null +++ b/src/rarpd.c @@ -0,0 +1,712 @@ +/* + * rarpd.c RARP daemon. + * + * 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. + * + * Authors: Alexey Kuznetsov, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iputils_common.h" + +int do_reload = 1; + +int debug; +int verbose; +int ifidx; +int allow_offlink; +int only_ethers; +int all_ifaces; +int listen_arp; +char *ifname; +char *tftp_dir = "/etc/tftpboot"; + +extern int ether_ntohost(char *name, unsigned char *ea); +void usage(void) __attribute__((noreturn)); + +struct iflink +{ + struct iflink *next; + int index; + int hatype; + unsigned char lladdr[16]; + char name[IFNAMSIZ]; + struct ifaddr *ifa_list; +} *ifl_list; + +struct ifaddr +{ + struct ifaddr *next; + uint32_t prefix; + uint32_t mask; + uint32_t local; +}; + +struct rarp_map +{ + struct rarp_map *next; + + int ifindex; + int arp_type; + int lladdr_len; + unsigned char lladdr[16]; + uint32_t ipaddr; +} *rarp_db; + +void usage(void) +{ + fprintf(stderr, + "\nUsage:\n" + " rarpd [options] [interface]\n" + "\nOptions:\n" + " -A listen also arp messages\n" + " -a listen on all the interfaces\n" + " -b tftpd boot directory\n" + " -d debug mode\n" + " -e /etc/ethers markup alone is fine\n" + " -v verbose mode\n" + " -V print version and exit\n" + "\nFor more details see rarpd(8).\n" + ); + exit(1); +} + +void load_db(void) +{ +} + +void load_if(void) +{ + int fd; + struct ifreq *ifrp, *ifend; + struct iflink *ifl; + struct ifaddr *ifa; + struct ifconf ifc; + struct ifreq ibuf[256]; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "socket: %s", strerror(errno)); + return; + } + + ifc.ifc_len = sizeof ibuf; + ifc.ifc_buf = (char *)ibuf; + if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || + ifc.ifc_len < (int)sizeof(struct ifreq)) { + syslog(LOG_ERR, "SIOCGIFCONF: %s", strerror(errno)); + close(fd); + return; + } + + while ((ifl = ifl_list) != NULL) { + while ((ifa = ifl->ifa_list) != NULL) { + ifl->ifa_list = ifa->next; + free(ifa); + } + ifl_list = ifl->next; + free(ifl); + } + + ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); + for (ifrp = ibuf; ifrp < ifend; ifrp++) { + uint32_t addr; + uint32_t mask; + uint32_t prefix; + + if (ifrp->ifr_addr.sa_family != AF_INET) + continue; + addr = ((struct sockaddr_in*)&ifrp->ifr_addr)->sin_addr.s_addr; + if (addr == 0) + continue; + if (ioctl(fd, SIOCGIFINDEX, ifrp)) { + syslog(LOG_ERR, "ioctl(SIOCGIFNAME): %s", strerror(errno)); + continue; + } + if (ifidx && ifrp->ifr_ifindex != ifidx) + continue; + for (ifl = ifl_list; ifl; ifl = ifl->next) + if (ifl->index == ifrp->ifr_ifindex) + break; + if (ifl == NULL) { + char *p; + int index = ifrp->ifr_ifindex; + + if (ioctl(fd, SIOCGIFHWADDR, ifrp)) { + syslog(LOG_ERR, "ioctl(SIOCGIFHWADDR): %s", strerror(errno)); + continue; + } + + ifl = (struct iflink*)malloc(sizeof(*ifl)); + if (ifl == NULL) + continue; + memset(ifl, 0, sizeof(*ifl)); + ifl->next = ifl_list; + ifl_list = ifl; + ifl->index = index; + ifl->hatype = ifrp->ifr_hwaddr.sa_family; + memcpy(ifl->lladdr, ifrp->ifr_hwaddr.sa_data, 14); + strncpy(ifl->name, ifrp->ifr_name, IFNAMSIZ); + p = strchr(ifl->name, ':'); + if (p) + *p = 0; + if (verbose) + syslog(LOG_INFO, "link %s", ifl->name); + } + if (ioctl(fd, SIOCGIFNETMASK, ifrp)) { + syslog(LOG_ERR, "ioctl(SIOCGIFMASK): %s", strerror(errno)); + continue; + } + mask = ((struct sockaddr_in*)&ifrp->ifr_netmask)->sin_addr.s_addr; + if (ioctl(fd, SIOCGIFDSTADDR, ifrp)) { + syslog(LOG_ERR, "ioctl(SIOCGIFDSTADDR): %s", strerror(errno)); + continue; + } + prefix = ((struct sockaddr_in*)&ifrp->ifr_dstaddr)->sin_addr.s_addr; + for (ifa = ifl->ifa_list; ifa; ifa = ifa->next) { + if (ifa->local == addr && + ifa->prefix == prefix && + ifa->mask == mask) + break; + } + if (ifa == NULL) { + if (mask == 0 || prefix == 0) + continue; + ifa = (struct ifaddr*)malloc(sizeof(*ifa)); + memset(ifa, 0, sizeof(*ifa)); + ifa->local = addr; + ifa->prefix = prefix; + ifa->mask = mask; + ifa->next = ifl->ifa_list; + ifl->ifa_list = ifa; + + if (verbose) { + int i; + uint32_t m = ~0U; + for (i=32; i>=0; i--) { + if (htonl(m) == mask) + break; + m <<= 1; + } + if (addr == prefix) { + syslog(LOG_INFO, " addr %s/%d on %s\n", + inet_ntoa(*(struct in_addr*)&addr), i, ifl->name); + } else { + char tmpa[64]; + sprintf(tmpa, "%s", inet_ntoa(*(struct in_addr*)&addr)); + syslog(LOG_INFO, " addr %s %s/%d on %s\n", tmpa, + inet_ntoa(*(struct in_addr*)&prefix), i, ifl->name); + } + } + } + } +} + +void configure(void) +{ + load_if(); + load_db(); +} + +int bootable(uint32_t addr) +{ + struct dirent *dent; + DIR *d; + char name[9]; + + sprintf(name, "%08X", (uint32_t)ntohl(addr)); + d = opendir(tftp_dir); + if (d == NULL) { + syslog(LOG_ERR, "opendir: %s", strerror(errno)); + return 0; + } + while ((dent = readdir(d)) != NULL) { + if (strncmp(dent->d_name, name, 8) == 0) + break; + } + closedir(d); + return dent != NULL; +} + +struct ifaddr *select_ipaddr(int ifindex, uint32_t *sel_addr, uint32_t **alist) +{ + struct iflink *ifl; + struct ifaddr *ifa; + int retry = 0; + int i; + +retry: + for (ifl=ifl_list; ifl; ifl=ifl->next) + if (ifl->index == ifindex) + break; + if (ifl == NULL && !retry) { + retry++; + load_if(); + goto retry; + } + if (ifl == NULL) + return NULL; + + for (i=0; alist[i]; i++) { + uint32_t addr = *(alist[i]); + for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) { + if (!((ifa->prefix^addr)&ifa->mask)) { + *sel_addr = addr; + return ifa; + } + } + if (ifa == NULL && retry==0) { + retry++; + load_if(); + goto retry; + } + } + if (i==1 && allow_offlink) { + *sel_addr = *(alist[0]); + return ifl->ifa_list; + } + syslog(LOG_ERR, "Off-link request on %s", ifl->name); + return NULL; +} + +struct rarp_map *rarp_lookup(int ifindex, int hatype, + int halen, unsigned char *lladdr) +{ + struct rarp_map *r; + + for (r=rarp_db; r; r=r->next) { + if (r->arp_type != hatype && r->arp_type != -1) + continue; + if (r->lladdr_len != halen) + continue; + if (r->ifindex != ifindex && r->ifindex != 0) + continue; + if (memcmp(r->lladdr, lladdr, halen) == 0) + break; + } + + if (r == NULL) { + if (hatype == ARPHRD_ETHER && halen == 6) { + struct ifaddr *ifa; + struct hostent *hp; + char ename[256]; + static struct rarp_map emap = { + .arp_type = ARPHRD_ETHER, + .lladdr_len = 6 + }; + + if (ether_ntohost(ename, lladdr) != 0 || + (hp = gethostbyname(ename)) == NULL) { + if (verbose) + syslog(LOG_INFO, "not found in /etc/ethers"); + return NULL; + } + if (hp->h_addrtype != AF_INET) { + syslog(LOG_ERR, "no IP address"); + return NULL; + } + ifa = select_ipaddr(ifindex, &emap.ipaddr, (uint32_t **)hp->h_addr_list); + if (ifa) { + memcpy(emap.lladdr, lladdr, 6); + if (only_ethers || bootable(emap.ipaddr)) + return &emap; + if (verbose) + syslog(LOG_INFO, "not bootable"); + } + } + } + return r; +} + +static int load_arp_bpflet(int fd) +{ + static struct sock_filter insns[] = { + BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ARPOP_RREQUEST, 0, 1), + BPF_STMT(BPF_RET|BPF_K, 1024), + BPF_STMT(BPF_RET|BPF_K, 0), + }; + static struct sock_fprog filter = { + sizeof insns / sizeof(insns[0]), + insns + }; + + return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); +} + +int put_mylladdr(unsigned char **ptr_p, int ifindex, int alen) +{ + struct iflink *ifl; + + for (ifl=ifl_list; ifl; ifl = ifl->next) + if (ifl->index == ifindex) + break; + + if (ifl==NULL) + return -1; + + memcpy(*ptr_p, ifl->lladdr, alen); + *ptr_p += alen; + return 0; +} + +int put_myipaddr(unsigned char **ptr_p, int ifindex, uint32_t hisipaddr) +{ + uint32_t laddr = 0; + struct iflink *ifl; + struct ifaddr *ifa; + + for (ifl=ifl_list; ifl; ifl = ifl->next) + if (ifl->index == ifindex) + break; + + if (ifl==NULL) + return -1; + + for (ifa=ifl->ifa_list; ifa; ifa=ifa->next) { + if (!((ifa->prefix^hisipaddr)&ifa->mask)) { + laddr = ifa->local; + break; + } + } + memcpy(*ptr_p, &laddr, 4); + *ptr_p += 4; + return 0; +} + +void arp_advise(int ifindex, unsigned char *lladdr, int lllen, uint32_t ipaddr) +{ + int fd; + struct arpreq req; + struct sockaddr_in *sin; + struct iflink *ifl; + + for (ifl=ifl_list; ifl; ifl = ifl->next) + if (ifl->index == ifindex) + break; + + if (ifl == NULL) + return; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + memset(&req, 0, sizeof(req)); + req.arp_flags = ATF_COM; + sin = (struct sockaddr_in *)&req.arp_pa; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = ipaddr; + req.arp_ha.sa_family = ifl->hatype; + memcpy(req.arp_ha.sa_data, lladdr, lllen); + memcpy(req.arp_dev, ifl->name, IFNAMSIZ); + + if (ioctl(fd, SIOCSARP, &req)) + syslog(LOG_ERR, "SIOCSARP: %s", strerror(errno)); + close(fd); +} + +void serve_it(int fd) +{ + unsigned char buf[1024]; + struct sockaddr_ll sll = { 0 }; + socklen_t sll_len = sizeof(sll); + struct arphdr *a = (struct arphdr*)buf; + struct rarp_map *rmap; + unsigned char *ptr; + ssize_t n; + + n = recvfrom(fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr*)&sll, &sll_len); + if (n<0) { + if (errno != EINTR && errno != EAGAIN) + syslog(LOG_ERR, "recvfrom: %s", strerror(errno)); + return; + } + + /* Do not accept packets for other hosts and our own ones */ + if (sll.sll_pkttype != PACKET_BROADCAST && + sll.sll_pkttype != PACKET_MULTICAST && + sll.sll_pkttype != PACKET_HOST) + return; + + if (ifidx && sll.sll_ifindex != ifidx) + return; + + if ((size_t)nar_op != htons(ARPOP_RREQUEST)) + return; + + if (verbose) { + int i; + char tmpbuf[16*3]; + char *p = tmpbuf; + for (i=0; i pln==4 */ + if (a->ar_pln != 4) { + syslog(LOG_ERR, "interesting rarp_req plen=%d", a->ar_pln); + return; + } + /* 2. ARP protocol must be IP */ + if (a->ar_pro != htons(ETH_P_IP)) { + syslog(LOG_ERR, "rarp protocol is not IP %04x", ntohs(a->ar_pro)); + return; + } + /* 3. ARP types must match */ + if (htons(sll.sll_hatype) != a->ar_hrd) { + switch (sll.sll_hatype) { + case ARPHRD_FDDI: + if (a->ar_hrd == htons(ARPHRD_ETHER) || + a->ar_hrd == htons(ARPHRD_IEEE802)) + break; + /* fallthrough */ + default: + syslog(LOG_ERR, "rarp htype mismatch"); + return; + } + } + /* 3. LL address lengths must be equal */ + if (a->ar_hln != sll.sll_halen) { + syslog(LOG_ERR, "rarp hlen mismatch"); + return; + } + /* 4. Check packet length */ + if (sizeof(*a) + 2*4 + 2*a->ar_hln > (size_t) n) { + syslog(LOG_ERR, "truncated rarp request; len=%zu", n); + return; + } + /* 5. Silly check: if this guy set different source + addresses in MAC header and in ARP, he is insane + */ + if (memcmp(sll.sll_addr, a+1, sll.sll_halen)) { + syslog(LOG_ERR, "this guy set different his lladdrs in arp and header"); + return; + } + /* End of sanity checks */ + + /* Lookup requested target in our database */ + rmap = rarp_lookup(sll.sll_ifindex, sll.sll_hatype, + sll.sll_halen, (unsigned char*)(a+1) + sll.sll_halen + 4); + if (rmap == NULL) + return; + + /* Prepare reply. It is almost ready, we only + replace ARP packet type, put our lladdr and + IP address to source fields, + and fill target IP address. + */ + a->ar_op = htons(ARPOP_RREPLY); + ptr = (unsigned char*)(a+1); + if (put_mylladdr(&ptr, sll.sll_ifindex, rmap->lladdr_len)) + return; + if (put_myipaddr(&ptr, sll.sll_ifindex, rmap->ipaddr)) + return; + /* It is already filled */ + ptr += rmap->lladdr_len; + memcpy(ptr, &rmap->ipaddr, 4); + ptr += 4; + + /* Update our ARP cache. Probably, this guy + will not able to make ARP (if it is broken) + */ + arp_advise(sll.sll_ifindex, rmap->lladdr, rmap->lladdr_len, rmap->ipaddr); + + /* Sendto is blocking, but with 5sec timeout */ + alarm(5); + sendto(fd, buf, ptr - buf, 0, (struct sockaddr*)&sll, sizeof(sll)); + alarm(0); +} + +void catch_signal(int sig, void (*handler)(int)) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handler; + sigaction(sig, &sa, NULL); +} + +void sig_alarm(int signo __attribute__((__unused__))) +{ +} + +void sig_hup(int signo __attribute__((__unused__))) +{ + do_reload = 1; +} + +int main(int argc, char **argv) +{ + struct pollfd pset[2]; + int psize; + int opt; + + atexit(close_stdout); + opterr = 0; + while ((opt = getopt(argc, argv, "aAb:dvoeV")) != EOF) { + switch (opt) { + case 'a': + ++all_ifaces; + break; + + case 'A': + ++listen_arp; + break; + + case 'd': + ++debug; + break; + + case 'v': + ++verbose; + break; + + case 'o': + ++allow_offlink; + break; + + case 'e': + ++only_ethers; + break; + + case 'b': + tftp_dir = optarg; + break; + case 'V': + printf(IPUTILS_VERSION("rarpd")); + return 0; + default: + usage(); + } + } + if (argc > optind) { + if (argc > optind+1) + usage(); + ifname = argv[optind]; + } + + psize = 1; + pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0); + + if (ifname) { + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(pset[0].fd, SIOCGIFINDEX, &ifr)) { + error(0, errno, "ioctl(SIOCGIFINDEX)"); + usage(); + } + ifidx = ifr.ifr_ifindex; + } + + pset[1].fd = -1; + if (listen_arp) { + pset[1].fd = socket(PF_PACKET, SOCK_DGRAM, 0); + if (pset[1].fd >= 0) { + load_arp_bpflet(pset[1].fd); + psize = 1; + } + } + + if (pset[1].fd >= 0) { + struct sockaddr_ll sll; + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_protocol = htons(ETH_P_ARP); + sll.sll_ifindex = all_ifaces ? 0 : ifidx; + if (bind(pset[1].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) { + close(pset[1].fd); + pset[1].fd = -1; + psize = 1; + } + } + if (pset[0].fd >= 0) { + struct sockaddr_ll sll; + memset(&sll, 0, sizeof(sll)); + sll.sll_family = AF_PACKET; + sll.sll_protocol = htons(ETH_P_RARP); + sll.sll_ifindex = all_ifaces ? 0 : ifidx; + if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) { + close(pset[0].fd); + pset[0].fd = -1; + } + } + if (pset[0].fd < 0) { + pset[0] = pset[1]; + psize--; + } + if (psize == 0) + error(1, errno, "failed to bind any socket"); + + if (!debug) { + if (daemon(0, 0) < 0) + error(1, errno, "failed to daemon()"); + } + + openlog("rarpd", LOG_PID | LOG_CONS, LOG_DAEMON); + catch_signal(SIGALRM, sig_alarm); + catch_signal(SIGHUP, sig_hup); + + for (;;) { + int i; + + if (do_reload) { + configure(); + do_reload = 0; + } + +#define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP) + pset[0].events = EVENTS; + pset[0].revents = 0; + pset[1].events = EVENTS; + pset[1].revents = 0; + + i = poll(pset, psize, -1); + if (i <= 0) { + if (errno != EINTR && i<0) { + syslog(LOG_ERR, "poll returned some crap: %s\n", strerror(errno)); + sleep(10); + } + continue; + } + for (i=0; i