--- /dev/null
+ 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.
+\f
+ 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.)
+\f
+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.
+\f
+ 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.
+\f
+ 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
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 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) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
fi
+for ac_hdr in linux/if.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1009: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1014 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1019: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
ac_aux_dir=
for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
if test -f $ac_dir/install-sh; then
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:1036: checking for a BSD compatible install" >&5
+echo "configure:1076: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-echo $ac_n "checking for pid_t""... $ac_c" 1>&6
-echo "configure:1089: checking for pid_t" >&5
-if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1094 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#endif
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
- rm -rf conftest*
- ac_cv_type_pid_t=yes
-else
- rm -rf conftest*
- ac_cv_type_pid_t=no
-fi
-rm -f conftest*
-
-fi
-echo "$ac_t""$ac_cv_type_pid_t" 1>&6
-if test $ac_cv_type_pid_t = no; then
- cat >> confdefs.h <<\EOF
-#define pid_t int
-EOF
-
-fi
-
-echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:1122: checking for size_t" >&5
-if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1127 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#endif
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
- rm -rf conftest*
- ac_cv_type_size_t=yes
-else
- rm -rf conftest*
- ac_cv_type_size_t=no
-fi
-rm -f conftest*
-
-fi
-echo "$ac_t""$ac_cv_type_size_t" 1>&6
-if test $ac_cv_type_size_t = no; then
- cat >> confdefs.h <<\EOF
-#define size_t unsigned
-EOF
-
-fi
-
-echo $ac_n "checking for vprintf""... $ac_c" 1>&6
-echo "configure:1155: checking for vprintf" >&5
-if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1160 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char vprintf(); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char vprintf();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub_vprintf) || defined (__stub___vprintf)
-choke me
-#else
-vprintf();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:1183: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func_vprintf=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func_vprintf=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_VPRINTF 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-
-if test "$ac_cv_func_vprintf" != yes; then
-echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
-echo "configure:1207: checking for _doprnt" >&5
-if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1212 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char _doprnt(); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char _doprnt();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub__doprnt) || defined (__stub____doprnt)
-choke me
-#else
-_doprnt();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:1235: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func__doprnt=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func__doprnt=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_DOPRNT 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-
-fi
-
-echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:1260: checking for working const" >&5
-if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1265 "configure"
-#include "confdefs.h"
-
-int main() {
-
-/* Ultrix mips cc rejects this. */
-typedef int charset[2]; const charset x;
-/* SunOS 4.1.1 cc rejects this. */
-char const *const *ccp;
-char **p;
-/* NEC SVR4.0.2 mips cc rejects this. */
-struct point {int x, y;};
-static struct point const zero = {0,0};
-/* AIX XL C 1.02.0.0 rejects this.
- It does not let you subtract one const X* pointer from another in an arm
- of an if-expression whose if-part is not a constant expression */
-const char *g = "string";
-ccp = &g + (g ? g-g : 0);
-/* HPUX 7.0 cc rejects these. */
-++ccp;
-p = (char**) ccp;
-ccp = (char const *const *) p;
-{ /* SCO 3.2v4 cc rejects this. */
- char *t;
- char const *s = 0 ? (char *) 0 : (char const *) 0;
-
- *t++ = 0;
-}
-{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
- int x[] = {25, 17};
- const int *foo = &x[0];
- ++foo;
-}
-{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
- typedef const int *iptr;
- iptr p = 0;
- ++p;
-}
-{ /* AIX XL C 1.02.0.0 rejects this saying
- "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
- struct s { int j; const int *ap[3]; };
- struct s *b; b->j = 5;
-}
-{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
- const int foo = 10;
-}
-
-; return 0; }
-EOF
-if { (eval echo configure:1314: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
- rm -rf conftest*
- ac_cv_c_const=yes
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- ac_cv_c_const=no
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_c_const" 1>&6
-if test $ac_cv_c_const = no; then
- cat >> confdefs.h <<\EOF
-#define const
-EOF
-
-fi
-
echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
-echo "configure:1335: checking whether byte ordering is bigendian" >&5
+echo "configure:1129: checking whether byte ordering is bigendian" >&5
if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_cv_c_bigendian=unknown
# See if sys/param.h defines the BYTE_ORDER macro.
cat > conftest.$ac_ext <<EOF
-#line 1342 "configure"
+#line 1136 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/param.h>
#endif
; return 0; }
EOF
-if { (eval echo configure:1353: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1147: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
# It does; now see whether it defined to BIG_ENDIAN or not.
cat > conftest.$ac_ext <<EOF
-#line 1357 "configure"
+#line 1151 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/param.h>
#endif
; return 0; }
EOF
-if { (eval echo configure:1368: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1162: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_bigendian=yes
else
{ echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
else
cat > conftest.$ac_ext <<EOF
-#line 1388 "configure"
+#line 1182 "configure"
#include "confdefs.h"
main () {
/* Are we little or big endian? From Harbison&Steele. */
exit (u.c[sizeof (long) - 1] == 1);
}
EOF
-if { (eval echo configure:1401: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1195: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
ac_cv_c_bigendian=no
else
echo $ac_n "checking for mpz_init_set_str in -lgmp2""... $ac_c" 1>&6
-echo "configure:1426: checking for mpz_init_set_str in -lgmp2" >&5
+echo "configure:1220: checking for mpz_init_set_str in -lgmp2" >&5
ac_lib_var=`echo gmp2'_'mpz_init_set_str | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lgmp2 $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1434 "configure"
+#line 1228 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
mpz_init_set_str()
; return 0; }
EOF
-if { (eval echo configure:1445: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1239: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
fi
echo $ac_n "checking for yywrap in -lfl""... $ac_c" 1>&6
-echo "configure:1473: checking for yywrap in -lfl" >&5
+echo "configure:1267: checking for yywrap in -lfl" >&5
ac_lib_var=`echo fl'_'yywrap | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-lfl $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1481 "configure"
+#line 1275 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
yywrap()
; return 0; }
EOF
-if { (eval echo configure:1492: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1286: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
fi
echo $ac_n "checking for adns_init in -ladns""... $ac_c" 1>&6
-echo "configure:1520: checking for adns_init in -ladns" >&5
+echo "configure:1314: checking for adns_init in -ladns" >&5
ac_lib_var=`echo adns'_'adns_init | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
ac_save_LIBS="$LIBS"
LIBS="-ladns $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1528 "configure"
+#line 1322 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
adns_init()
; return 0; }
EOF
-if { (eval echo configure:1539: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1333: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
/* User-kernel network link */
-/* We support a variety of methods: userv-ipif, ipif on its own (when
- we run as root), SLIP to a pty, an external netlink daemon. There
- is a performance/security tradeoff. */
+/* We will eventually support a variety of methods for extracting
+ packets from the kernel: userv-ipif, ipif on its own (when we run
+ as root), the kernel TUN driver, SLIP to a pty, an external netlink
+ daemon. There is a performance/security tradeoff. */
/* When dealing with SLIP (to a pty, or ipif) we have separate rx, tx
and client buffers. When receiving we may read() any amount, not
and may be part-way through receiving. */
/* Each netlink device is actually a router, with its own IP
- address. We should eventually do things like decreasing the TTL and
- recalculating the header checksum, generating ICMP, responding to
- pings, etc. but for now we can get away without them. We should
- implement this stuff no matter how we get the packets to/from the
- kernel. */
+ address. We do things like decreasing the TTL and recalculating the
+ header checksum, generating ICMP, responding to pings, etc. */
/* This is where we have the anti-spoofing paranoia - before sending a
packet to the kernel we check that the tunnel it came over could
reasonably have produced it. */
+/* XXX now implement TUN. Kernel needs recompiling. */
+
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "config.h"
#include "secnet.h"
#include "util.h"
+#ifdef HAVE_LINUX_IF_H
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#endif
+
+/* XXX where do we find if_tun on other architectures? */
+
#define DEFAULT_BUFSIZE 2048
+#define DEFAULT_MTU 1000
+#define ICMP_BUFSIZE 1024
#define SLIP_END 192
#define SLIP_ESC 219
struct subnet_list *networks;
netlink_deliver_fn *deliver;
void *dst;
+ string_t name;
+ bool_t can_deliver;
struct netlink_client *next;
};
-struct userv {
+/* Netlink provides one function to the device driver, to call to deliver
+ a packet from the device. The device driver provides one function to
+ netlink, for it to call to deliver a packet to the device. */
+
+struct netlink {
closure_t cl;
struct netlink_if ops;
+ void *dst; /* Pointer to host interface state */
+ string_t name;
uint32_t max_start_pad;
uint32_t max_end_pad;
- int txfd; /* We transmit to userv */
- int rxfd; /* We receive from userv */
- struct netlink_client *clients;
- string_t name;
- string_t userv_path;
- string_t service_user;
- string_t service_name;
struct subnet_list networks;
- uint32_t local_address;
- uint32_t secnet_address;
+ uint32_t local_address; /* host interface address */
+ uint32_t secnet_address; /* our own address */
uint32_t mtu;
- uint32_t txbuflen;
- struct buffer_if *buff; /* We unstuff received packets into here
- and send them to the site code. */
- bool_t pending_esc;
+ struct netlink_client *clients;
+ netlink_deliver_fn *deliver_to_host; /* Provided by driver */
+ struct buffer_if icmp; /* Buffer for assembly of outgoing ICMP */
};
-static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
- int *timeout_io, const struct timeval *tv_now,
- uint64_t *now)
+/* Generic IP checksum routine */
+static inline uint16_t ip_csum(uint8_t *iph,uint32_t count)
{
- struct userv *st=sst;
- *nfds_io=2;
- fds[0].fd=st->txfd;
- fds[0].events=POLLERR; /* Might want to pick up POLLOUT sometime */
- fds[1].fd=st->rxfd;
- fds[1].events=POLLIN|POLLERR|POLLHUP;
- return 0;
+ register uint32_t sum=0;
+
+ while (count>1) {
+ sum+=ntohs(*(uint16_t *)iph);
+ iph+=2;
+ count-=2;
+ }
+ if(count>0)
+ sum+=*(uint8_t *)iph;
+ while (sum>>16)
+ sum=(sum&0xffff)+(sum>>16);
+ return htons(~sum);
}
-static void process_local_packet(struct userv *st)
+#ifdef i386
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ *
+ * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
+ * Arnt Gulbrandsen.
+ */
+static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl) {
+ uint32_t sum;
+
+ __asm__ __volatile__("
+ movl (%1), %0
+ subl $4, %2
+ jbe 2f
+ addl 4(%1), %0
+ adcl 8(%1), %0
+ adcl 12(%1), %0
+1: adcl 16(%1), %0
+ lea 4(%1), %1
+ decl %2
+ jne 1b
+ adcl $0, %0
+ movl %0, %2
+ shrl $16, %0
+ addw %w2, %w0
+ adcl $0, %0
+ notl %0
+2:
+ "
+ /* Since the input registers which are loaded with iph and ipl
+ are modified, we must also specify them as outputs, or gcc
+ will assume they contain their original values. */
+ : "=r" (sum), "=r" (iph), "=r" (ihl)
+ : "1" (iph), "2" (ihl));
+ return sum;
+}
+#else
+static inline uint16_t ip_fast_csum(uint8_t *iph, uint32_t ihl)
{
- uint32_t source,dest;
+ return ip_csum(iph,ihl*4);
+}
+#endif
+
+struct iphdr {
+#if defined (WORDS_BIGENDIAN)
+ uint8_t version:4,
+ ihl:4;
+#else
+ uint8_t ihl:4,
+ version:4;
+#endif
+ uint8_t tos;
+ uint16_t tot_len;
+ uint16_t id;
+ uint16_t frag_off;
+ uint8_t ttl;
+ uint8_t protocol;
+ uint16_t check;
+ uint32_t saddr;
+ uint32_t daddr;
+ /* The options start here. */
+};
+
+struct icmphdr {
+ struct iphdr iph;
+ uint8_t type;
+ uint8_t code;
+ uint16_t check;
+ union {
+ uint32_t unused;
+ struct {
+ uint8_t pointer;
+ uint8_t unused1;
+ uint16_t unused2;
+ } pprob;
+ uint32_t gwaddr;
+ struct {
+ uint16_t id;
+ uint16_t seq;
+ } echo;
+ } d;
+};
+
+static void netlink_packet_deliver(struct netlink *st, struct buffer_if *buf);
+
+static struct icmphdr *netlink_icmp_tmpl(struct netlink *st,
+ uint32_t dest,uint16_t len)
+{
+ struct icmphdr *h;
+
+ BUF_ALLOC(&st->icmp,"netlink_icmp_tmpl");
+ buffer_init(&st->icmp,st->max_start_pad);
+ h=buf_append(&st->icmp,sizeof(*h));
+
+ h->iph.version=4;
+ h->iph.ihl=5;
+ h->iph.tos=0;
+ h->iph.tot_len=htons(len+(h->iph.ihl*4)+8);
+ h->iph.id=0;
+ h->iph.frag_off=0;
+ h->iph.ttl=255;
+ h->iph.protocol=1;
+ h->iph.saddr=htonl(st->secnet_address);
+ h->iph.daddr=htonl(dest);
+ h->iph.check=0;
+ h->iph.check=ip_fast_csum((uint8_t *)&h->iph,h->iph.ihl);
+ h->check=0;
+ h->d.unused=0;
+
+ return h;
+}
+
+/* Fill in the ICMP checksum field correctly */
+static void netlink_icmp_csum(struct icmphdr *h)
+{
+ uint32_t len;
+
+ len=ntohs(h->iph.tot_len)-(4*h->iph.ihl);
+ h->check=0;
+ h->check=ip_csum(&h->type,len);
+}
+
+/* RFC1122:
+ * An ICMP error message MUST NOT be sent as the result of
+ * receiving:
+ *
+ * * an ICMP error message, or
+ *
+ * * a datagram destined to an IP broadcast or IP multicast
+ * address, or
+ *
+ * * a datagram sent as a link-layer broadcast, or
+ *
+ * * a non-initial fragment, or
+ *
+ * * a datagram whose source address does not define a single
+ * host -- e.g., a zero address, a loopback address, a
+ * broadcast address, a multicast address, or a Class E
+ * address.
+ */
+static bool_t netlink_icmp_may_reply(struct buffer_if *buf)
+{
+ struct iphdr *iph;
+ uint32_t source;
+
+ iph=(struct iphdr *)buf->start;
+ if (iph->protocol==1) return False; /* Overly-broad; we may reply to
+ eg. icmp echo-request */
+ /* How do we spot broadcast destination addresses? */
+ if (ntohs(iph->frag_off)&0x1fff) return False; /* Non-initial fragment */
+ source=ntohl(iph->saddr);
+ if (source==0) return False;
+ if ((source&0xff000000)==0x7f000000) return False;
+ /* How do we spot broadcast source addresses? */
+ if ((source&0xf0000000)==0xe0000000) return False; /* Multicast */
+ if ((source&0xf0000000)==0xf0000000) return False; /* Class E */
+ return True;
+}
+
+/* How much of the original IP packet do we include in its ICMP
+ response? The header plus up to 64 bits. */
+static uint16_t netlink_icmp_reply_len(struct buffer_if *buf)
+{
+ struct iphdr *iph=(struct iphdr *)buf->start;
+ uint16_t hlen,plen;
+
+ hlen=iph->ihl*4;
+ /* We include the first 8 bytes of the packet data, provided they exist */
+ hlen+=8;
+ plen=ntohs(iph->tot_len);
+ return (hlen>plen?plen:hlen);
+}
+
+static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
+ uint8_t type, uint8_t code)
+{
+ struct iphdr *iph=(struct iphdr *)buf->start;
+ struct icmphdr *h;
+ uint16_t len;
+
+ if (netlink_icmp_may_reply(buf)) {
+ len=netlink_icmp_reply_len(buf);
+ h=netlink_icmp_tmpl(st,ntohl(iph->saddr),len);
+ h->type=type; h->code=code;
+ memcpy(buf_append(&st->icmp,len),buf->start,len);
+ netlink_icmp_csum(h);
+ netlink_packet_deliver(st,&st->icmp);
+ BUF_ASSERT_FREE(&st->icmp);
+ }
+}
+
+/*
+ * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the
+ * checksum.
+ *
+ * Is the datagram acceptable?
+ *
+ * 1. Length at least the size of an ip header
+ * 2. Version of 4
+ * 3. Checksums correctly.
+ * 4. Doesn't have a bogus length
+ */
+static bool_t netlink_check(struct netlink *st, struct buffer_if *buf)
+{
+ struct iphdr *iph=(struct iphdr *)buf->start;
+ uint32_t len;
+
+ if (iph->ihl < 5 || iph->version != 4) {
+ printf("ihl/version check failed\n");
+ return False;
+ }
+ if (buf->size < iph->ihl*4) {
+ printf("buffer size check failed\n");
+ return False;
+ }
+ if (ip_fast_csum((uint8_t *)iph, iph->ihl)!=0) {
+ printf("checksum failed\n");
+ return False;
+ }
+ len=ntohs(iph->tot_len);
+ /* There should be no padding */
+ if (buf->size!=len || len<(iph->ihl<<2)) {
+ printf("length check failed buf->size=%d len=%d\n",buf->size,len);
+ return False;
+ }
+
+ /* XXX check that there's no source route specified */
+ return True;
+}
+
+static void netlink_packet_deliver(struct netlink *st, struct buffer_if *buf)
+{
+ struct iphdr *iph=(struct iphdr *)buf->start;
+ uint32_t dest=ntohl(iph->daddr);
struct netlink_client *c;
- source=ntohl(*(uint32_t *)(st->buff->start+12));
- dest=ntohl(*(uint32_t *)(st->buff->start+16));
+ BUF_ASSERT_USED(buf);
-/* printf("process_local_packet source=%s dest=%s len=%d\n",
- ipaddr_to_string(source),ipaddr_to_string(dest),
- st->buff->size); */
- if (!subnet_match(&st->networks,source)) {
- string_t s,d;
- s=ipaddr_to_string(source);
- d=ipaddr_to_string(dest);
- Message(M_WARNING,"%s: outgoing packet with bad source address "
- "(s=%s,d=%s)\n",st->name,s,d);
- free(s); free(d);
+ if (dest==st->secnet_address) {
+ Message(M_ERROR,"%s: trying to deliver a packet to myself!\n");
+ BUF_FREE(buf);
return;
}
+
for (c=st->clients; c; c=c->next) {
if (subnet_match(c->networks,dest)) {
- c->deliver(c->dst,c,st->buff);
- BUF_ALLOC(st->buff,"netlink:process_local_packet");
+ if (c->can_deliver) {
+ c->deliver(c->dst,c,buf);
+ BUF_ASSERT_FREE(buf);
+ } else {
+ /* Generate ICMP destination unreachable */
+ netlink_icmp_simple(st,buf,3,0);
+ BUF_FREE(buf);
+ }
return;
}
}
+ if (subnet_match(&st->networks,dest)) {
+ st->deliver_to_host(st->dst,NULL,buf);
+ BUF_ASSERT_FREE(buf);
+ return;
+ }
+ Message(M_ERROR,"%s: failed to deliver a packet (bad destination address)"
+ "\nXXX make this message clearer\n");
+ BUF_FREE(buf);
+}
+
+static void netlink_packet_forward(struct netlink *st, struct buffer_if *buf)
+{
+ struct iphdr *iph=(struct iphdr *)buf->start;
+
+ BUF_ASSERT_USED(buf);
+
+ /* Packet has already been checked */
+ if (iph->ttl<=1) {
+ /* Generate ICMP time exceeded */
+ netlink_icmp_simple(st,buf,11,0);
+ BUF_FREE(buf);
+ return;
+ }
+ iph->ttl--;
+ iph->check=0;
+ iph->check=ip_fast_csum((uint8_t *)iph,iph->ihl);
+
+ netlink_packet_deliver(st,buf);
+ BUF_ASSERT_FREE(buf);
+}
+
+/* Someone has been foolish enough to address a packet to us. I
+ suppose we should reply to it, just to be polite. */
+static void netlink_packet_local(struct netlink *st, struct buffer_if *buf)
+{
+ struct icmphdr *h;
+
+ h=(struct icmphdr *)buf->start;
+
+ if ((ntohs(h->iph.frag_off)&0xbfff)!=0) {
+ Message(M_WARNING,"%s: fragmented packet addressed to us\n",st->name);
+ BUF_FREE(buf);
+ return;
+ }
+
+ if (h->iph.protocol==1) {
+ /* It's ICMP */
+ if (h->type==8 && h->code==0) {
+ /* ICMP echo-request. Special case: we re-use the buffer
+ to construct the reply. */
+ h->type=0;
+ h->iph.daddr=h->iph.saddr;
+ h->iph.saddr=htonl(st->secnet_address);
+ h->iph.ttl=255; /* Be nice and bump it up again... */
+ h->iph.check=0;
+ h->iph.check=ip_fast_csum((uint8_t *)h,h->iph.ihl);
+ netlink_icmp_csum(h);
+ netlink_packet_deliver(st,buf);
+ return;
+ }
+ Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
+ } else {
+ /* Send ICMP protocol unreachable */
+ netlink_icmp_simple(st,buf,3,2);
+ BUF_FREE(buf);
+ return;
+ }
+
+ BUF_FREE(buf);
+}
+
+/* Called by site code when remote packet is available */
+/* buf is allocated on entry and free on return */
+static void netlink_from_tunnel(void *sst, void *cst, struct buffer_if *buf)
+{
+ struct netlink *st=sst;
+ struct netlink_client *client=cst;
+ uint32_t source,dest;
+ struct iphdr *iph;
+
+ BUF_ASSERT_USED(buf);
+ if (!netlink_check(st,buf)) {
+ Message(M_WARNING,"%s: bad IP packet from tunnel %s\n",
+ st->name,client->name);
+ BUF_FREE(buf);
+ return;
+ }
+ iph=(struct iphdr *)buf->start;
+
+ source=ntohl(iph->saddr);
+ dest=ntohl(iph->daddr);
+
+ /* Check that the packet source is in 'nets' and its destination is
+ in client->networks */
+ if (!subnet_match(client->networks,source)) {
+ string_t s,d;
+ s=ipaddr_to_string(source);
+ d=ipaddr_to_string(dest);
+ Message(M_WARNING,"%s: packet from tunnel %s with bad source address "
+ "(s=%s,d=%s)\n",st->name,client->name,s,d);
+ free(s); free(d);
+ BUF_FREE(buf);
+ return;
+ }
+ /* (st->secnet_address needs checking before matching against
+ st->networks because secnet's IP address may not be in the
+ range the host is willing to deal with) */
if (dest==st->secnet_address) {
- printf("%s: secnet received packet of len %d from %s\n",st->name,
- st->buff->size,ipaddr_to_string(source));
+ netlink_packet_local(st,buf);
+ BUF_ASSERT_FREE(buf);
return;
}
- {
+ if (!subnet_match(&st->networks,dest)) {
string_t s,d;
s=ipaddr_to_string(source);
d=ipaddr_to_string(dest);
- Message(M_WARNING,"%s: outgoing packet with bad destination address "
- "(s=%s,d=%s)\n",st->name,s,d);
+ Message(M_WARNING,"%s: incoming packet from tunnel %s "
+ "with bad destination address "
+ "(s=%s,d=%s)\n",st->name,client->name,s,d);
free(s); free(d);
+ BUF_FREE(buf);
return;
}
+
+ netlink_packet_forward(st,buf);
+
+ BUF_ASSERT_FREE(buf);
+}
+
+/* Called by driver code when packet is received from kernel */
+/* cid should be NULL */
+/* buf should be allocated on entry, and is free on return */
+static void netlink_from_host(void *sst, void *cid, struct buffer_if *buf)
+{
+ struct netlink *st=sst;
+ uint32_t source,dest;
+ struct iphdr *iph;
+
+ BUF_ASSERT_USED(buf);
+ if (!netlink_check(st,buf)) {
+ Message(M_WARNING,"%s: bad IP packet from host\n",
+ st->name);
+ BUF_FREE(buf);
+ return;
+ }
+ iph=(struct iphdr *)buf->start;
+
+ source=ntohl(iph->saddr);
+ dest=ntohl(iph->daddr);
+
+ if (!subnet_match(&st->networks,source)) {
+ string_t s,d;
+ s=ipaddr_to_string(source);
+ d=ipaddr_to_string(dest);
+ Message(M_WARNING,"%s: outgoing packet with bad source address "
+ "(s=%s,d=%s)\n",st->name,s,d);
+ free(s); free(d);
+ BUF_FREE(buf);
+ return;
+ }
+ if (dest==st->secnet_address) {
+ netlink_packet_local(st,buf);
+ BUF_ASSERT_FREE(buf);
+ return;
+ }
+ netlink_packet_forward(st,buf);
+ BUF_ASSERT_FREE(buf);
+}
+
+static void netlink_set_delivery(void *sst, void *cid, bool_t can_deliver)
+{
+ struct netlink_client *c=cid;
+
+ c->can_deliver=can_deliver;
+}
+
+static void *netlink_regnets(void *sst, struct subnet_list *nets,
+ netlink_deliver_fn *deliver, void *dst,
+ uint32_t max_start_pad, uint32_t max_end_pad,
+ string_t client_name)
+{
+ struct netlink *st=sst;
+ struct netlink_client *c;
+
+ Message(M_DEBUG_CONFIG,"netlink_regnets: request for %d networks, "
+ "max_start_pad=%d, max_end_pad=%d\n",
+ nets->entries,max_start_pad,max_end_pad);
+
+ c=safe_malloc(sizeof(*c),"netlink_regnets");
+ c->networks=nets;
+ c->deliver=deliver;
+ c->dst=dst;
+ c->name=client_name; /* XXX copy it? */
+ c->can_deliver=False;
+ c->next=st->clients;
+ st->clients=c;
+ if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
+ if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
+
+ return c;
+}
+
+static netlink_deliver_fn *netlink_init(struct netlink *st,
+ void *dst, struct cloc loc,
+ dict_t *dict, string_t description,
+ netlink_deliver_fn *to_host)
+{
+ st->dst=dst;
+ st->cl.description=description;
+ st->cl.type=CL_NETLINK;
+ st->cl.apply=NULL;
+ st->cl.interface=&st->ops;
+ st->ops.st=st;
+ st->ops.regnets=netlink_regnets;
+ st->ops.deliver=netlink_from_tunnel;
+ st->ops.set_delivery=netlink_set_delivery;
+ st->max_start_pad=0;
+ st->max_end_pad=0;
+ st->clients=NULL;
+ st->deliver_to_host=to_host;
+
+ st->name=dict_read_string(dict,"name",False,"netlink",loc);
+ if (!st->name) st->name=description;
+ dict_read_subnet_list(dict, "networks", True, "netlink", loc,
+ &st->networks);
+ st->local_address=string_to_ipaddr(
+ dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
+ st->secnet_address=string_to_ipaddr(
+ dict_find_item(dict,"secnet-address", True, "netlink", loc),"netlink");
+ if (!subnet_match(&st->networks,st->local_address)) {
+ cfgfatal(loc,"netlink","local-address must be in local networks\n");
+ }
+ st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
+ buffer_new(&st->icmp,ICMP_BUFSIZE);
+
+ return netlink_from_host;
+}
+
+/* Connection to the kernel through userv-ipif */
+
+struct userv {
+ struct netlink nl;
+ int txfd; /* We transmit to userv */
+ int rxfd; /* We receive from userv */
+ string_t userv_path;
+ string_t service_user;
+ string_t service_name;
+ uint32_t txbuflen;
+ struct buffer_if *buff; /* We unstuff received packets into here
+ and send them to the site code. */
+ bool_t pending_esc;
+ netlink_deliver_fn *netlink_to_tunnel;
+};
+
+static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
+ int *timeout_io, const struct timeval *tv_now,
+ uint64_t *now)
+{
+ struct userv *st=sst;
+ *nfds_io=2;
+ fds[0].fd=st->txfd;
+ fds[0].events=POLLERR; /* Might want to pick up POLLOUT sometime */
+ fds[1].fd=st->rxfd;
+ fds[1].events=POLLIN|POLLERR|POLLHUP;
+ return 0;
}
static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds,
}
/* XXX really crude unstuff code */
/* XXX check for buffer overflow */
+ BUF_ASSERT_USED(st->buff);
for (i=0; i<l; i++) {
if (st->pending_esc) {
st->pending_esc=False;
} else {
switch (rxbuf[i]) {
case SLIP_END:
- if (st->buff->size>0) process_local_packet(st);
- BUF_ASSERT_USED(st->buff);
- buffer_init(st->buff,st->max_start_pad);
+ if (st->buff->size>0) {
+ st->netlink_to_tunnel(&st->nl,NULL,
+ st->buff);
+ BUF_ALLOC(st->buff,"userv_afterpoll");
+ }
+ buffer_init(st->buff,st->nl.max_start_pad);
break;
case SLIP_ESC:
st->pending_esc=True;
}
}
}
- return;
+}
+
+/* Send buf to the kernel. Free buf before returning. */
+static void userv_deliver_to_kernel(void *sst, void *cid,
+ struct buffer_if *buf)
+{
+ struct userv *st=sst;
+ uint8_t txbuf[DEFAULT_BUFSIZE];
+ uint8_t *i;
+ uint32_t j;
+
+ BUF_ASSERT_USED(buf);
+
+ /* Spit the packet at userv-ipif: SLIP start marker, then
+ bytestuff the packet, then SLIP end marker */
+ /* XXX crunchy bytestuff code */
+ j=0;
+ txbuf[j++]=SLIP_END;
+ for (i=buf->start; i<(buf->start+buf->size); i++) {
+ switch (*i) {
+ case SLIP_END:
+ txbuf[j++]=SLIP_ESC;
+ txbuf[j++]=SLIP_ESCEND;
+ break;
+ case SLIP_ESC:
+ txbuf[j++]=SLIP_ESC;
+ txbuf[j++]=SLIP_ESCESC;
+ break;
+ default:
+ txbuf[j++]=*i;
+ break;
+ }
+ }
+ txbuf[j++]=SLIP_END;
+ if (write(st->txfd,txbuf,j)<0) {
+ fatal_perror("userv_deliver_to_kernel: write()");
+ }
+ BUF_FREE(buf);
}
static void userv_phase_hook(void *sst, uint32_t newphase)
be using should already have been registered. */
addrs=safe_malloc(512,"userv_phase_hook:addrs");
- snprintf(addrs,512,"%s,%s,%d,slip",ipaddr_to_string(st->local_address),
- ipaddr_to_string(st->secnet_address),st->mtu);
+ snprintf(addrs,512,"%s,%s,%d,slip",ipaddr_to_string(st->nl.local_address),
+ ipaddr_to_string(st->nl.secnet_address),st->nl.mtu);
nets=safe_malloc(1024,"userv_phase_hook:nets");
*nets=0;
- for (c=st->clients; c; c=c->next) {
+ for (c=st->nl.clients; c; c=c->next) {
for (i=0; i<c->networks->entries; i++) {
s=subnet_to_string(&c->networks->list[i]);
strcat(nets,s);
/* We are the parent... */
/* Register for poll() */
- register_for_poll(st, userv_beforepoll, userv_afterpoll, 2, "netlink");
+ register_for_poll(st, userv_beforepoll, userv_afterpoll, 2, st->nl.name);
}
-static void *userv_regnets(void *sst, struct subnet_list *nets,
- netlink_deliver_fn *deliver, void *dst,
- uint32_t max_start_pad, uint32_t max_end_pad)
+static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context,
+ list_t *args)
{
- struct userv *st=sst;
- struct netlink_client *c;
+ struct userv *st;
+ item_t *item;
+ dict_t *dict;
- Message(M_DEBUG_CONFIG,"userv_regnets: request for %d networks, "
- "max_start_pad=%d, max_end_pad=%d\n",
- nets->entries,max_start_pad,max_end_pad);
+ st=safe_malloc(sizeof(*st),"userv_apply");
- c=safe_malloc(sizeof(*c),"userv_regnets");
- c->networks=nets;
- c->deliver=deliver;
- c->dst=dst;
- c->next=st->clients;
- st->clients=c;
- if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
- if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
+ /* First parameter must be a dict */
+ item=list_elem(args,0);
+ if (!item || item->type!=t_dict)
+ cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n");
+
+ dict=item->data.dict;
- return c;
+ st->netlink_to_tunnel=
+ netlink_init(&st->nl,st,loc,dict,
+ "netlink-userv-ipif",userv_deliver_to_kernel);
+
+ st->userv_path=dict_read_string(dict,"userv-path",False,"userv-netlink",
+ loc);
+ st->service_user=dict_read_string(dict,"service-user",False,
+ "userv-netlink",loc);
+ st->service_name=dict_read_string(dict,"service-name",False,
+ "userv-netlink",loc);
+ if (!st->userv_path) st->userv_path="userv";
+ if (!st->service_user) st->service_user="root";
+ if (!st->service_name) st->service_name="ipif";
+ st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"userv-netlink",loc);
+ BUF_ALLOC(st->buff,"netlink:userv_apply");
+
+ st->rxfd=-1; st->txfd=-1;
+ add_hook(PHASE_DROPPRIV,userv_phase_hook,st);
+
+ return new_closure(&st->nl.cl);
}
-static void userv_deliver(void *sst, void *cid, struct buffer_if *buf)
-{
- struct userv *st=sst;
- struct netlink_client *client=cid;
- uint8_t txbuf[DEFAULT_BUFSIZE];
+/* Connection to the kernel through the universal TUN/TAP driver */
- uint32_t source,dest;
- uint8_t *i;
- uint32_t j;
+struct tun {
+ struct netlink nl;
+ int fd;
+ string_t device_path;
+ string_t interface_name;
+ string_t ifconfig_path;
+ string_t route_path;
+ struct buffer_if *buff; /* We receive packets into here
+ and send them to the netlink code. */
+ netlink_deliver_fn *netlink_to_tunnel;
+};
- source=ntohl(*(uint32_t *)(buf->start+12));
- dest=ntohl(*(uint32_t *)(buf->start+16));
+static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
+ int *timeout_io, const struct timeval *tv_now,
+ uint64_t *now)
+{
+ struct tun *st=sst;
+ *nfds_io=1;
+ fds[0].fd=st->fd;
+ fds[0].events=POLLIN|POLLERR|POLLHUP;
+ return 0;
+}
- /* Check that the packet source is in 'nets' and its destination is
- in client->networks */
- if (!subnet_match(client->networks,source)) {
- string_t s,d;
- s=ipaddr_to_string(source);
- d=ipaddr_to_string(dest);
- Message(M_WARNING,"%s: incoming packet with bad source address "
- "(s=%s,d=%s)\n",st->name,s,d);
- free(s); free(d);
- return;
+static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds,
+ const struct timeval *tv_now, uint64_t *now)
+{
+ struct tun *st=sst;
+ int l;
+
+ if (fds[0].revents&POLLERR) {
+ printf("tun_afterpoll: hup!\n");
}
- if (!subnet_match(&st->networks,dest)) {
- string_t s,d;
- s=ipaddr_to_string(source);
- d=ipaddr_to_string(dest);
- Message(M_WARNING,"%s: incoming packet with bad destination address "
- "(s=%s,d=%s)\n",st->name,s,d);
- free(s); free(d);
- return;
+ if (fds[0].revents&POLLIN) {
+ BUF_ALLOC(st->buff,"tun_afterpoll");
+ buffer_init(st->buff,st->nl.max_start_pad);
+ l=read(st->fd,st->buff->start,st->buff->len-st->nl.max_start_pad);
+ if (l<0) {
+ fatal_perror("tun_afterpoll: read()");
+ }
+ if (l==0) {
+ fatal("tun_afterpoll: read()=0; device gone away?\n");
+ }
+ if (l>0) {
+ st->buff->size=l;
+ st->netlink_to_tunnel(&st->nl,NULL,st->buff);
+ BUF_ASSERT_FREE(st->buff);
+ }
}
+}
- /* Really we should decrease TTL, check it's above zero, and
- recalculate header checksum here. If it gets down to zero,
- generate an ICMP time-exceeded and send the new packet back to
- the originating tunnel. XXX check buffer usage! */
+static void tun_deliver_to_kernel(void *sst, void *cid,
+ struct buffer_if *buf)
+{
+ struct tun *st=sst;
- /* (Basically do full IP packet forwarding stuff. Except that we
- know any packet passed in here is destined for the local
- machine; only exception is if it's destined for us.) */
+ BUF_ASSERT_USED(buf);
- if (dest==st->secnet_address) {
- printf("%s: incoming tunneled packet for secnet!\n",st->name);
- return;
- }
+ /* No error checking, because we'd just throw the packet away anyway */
+ write(st->fd,buf->start,buf->size);
+ BUF_FREE(buf);
+}
- /* Now spit the packet at userv-ipif: SLIP start marker, then
- bytestuff the packet, then SLIP end marker */
- /* XXX crunchy bytestuff code */
- j=0;
- txbuf[j++]=SLIP_END;
- for (i=buf->start; i<(buf->start+buf->size); i++) {
- switch (*i) {
- case SLIP_END:
- txbuf[j++]=SLIP_ESC;
- txbuf[j++]=SLIP_ESCEND;
- break;
- case SLIP_ESC:
- txbuf[j++]=SLIP_ESC;
- txbuf[j++]=SLIP_ESCESC;
- break;
- default:
- txbuf[j++]=*i;
- break;
+static void tun_phase_hook(void *sst, uint32_t newphase)
+{
+ struct tun *st=sst;
+ string_t hostaddr,secnetaddr;
+ uint8_t mtu[6];
+ string_t network,mask;
+ struct netlink_client *c;
+ int i;
+
+ /* All the networks we'll be using have been registered. Invoke ifconfig
+ to set the TUN device's address, and route to add routes to all
+ our networks. */
+
+ hostaddr=ipaddr_to_string(st->nl.local_address);
+ secnetaddr=ipaddr_to_string(st->nl.secnet_address);
+ snprintf(mtu,6,"%d",st->nl.mtu);
+ mtu[5]=0;
+
+ sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
+ hostaddr,"netmask","255.255.255.255","-broadcast",
+ "pointopoint",secnetaddr,"mtu",mtu,"up",(char *)0);
+
+ for (c=st->nl.clients; c; c=c->next) {
+ for (i=0; i<c->networks->entries; i++) {
+ network=ipaddr_to_string(c->networks->list[i].prefix);
+ mask=ipaddr_to_string(c->networks->list[i].mask);
+ sys_cmd(st->route_path,"route","add","-net",network,
+ "netmask",mask,"gw",secnetaddr,(char *)0);
}
}
- txbuf[j++]=SLIP_END;
- if (write(st->txfd,txbuf,j)<0) {
- fatal_perror("userv_deliver: write()");
+
+ /* Register for poll() */
+ register_for_poll(st, tun_beforepoll, tun_afterpoll, 1, st->nl.name);
+}
+
+#ifdef HAVE_LINUX_IF_H
+static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
+ list_t *args)
+{
+ struct tun *st;
+ item_t *item;
+ dict_t *dict;
+ struct ifreq ifr;
+
+ st=safe_malloc(sizeof(*st),"tun_apply");
+
+ /* First parameter must be a dict */
+ item=list_elem(args,0);
+ if (!item || item->type!=t_dict)
+ cfgfatal(loc,"tun","parameter must be a dictionary\n");
+
+ dict=item->data.dict;
+
+ st->netlink_to_tunnel=
+ netlink_init(&st->nl,st,loc,dict,
+ "netlink-tun",tun_deliver_to_kernel);
+
+ st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
+ st->interface_name=dict_read_string(dict,"interface",False,
+ "tun-netlink",loc);
+ st->ifconfig_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
+ st->route_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
+
+ if (!st->device_path) st->device_path="/dev/net/tun";
+ if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
+ if (!st->route_path) st->route_path="route";
+ st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
+
+ /* New TUN interface: open the device, then do ioctl TUNSETIFF
+ to set or find out the network interface name. */
+ st->fd=open(st->device_path,O_RDWR);
+ if (st->fd==-1) {
+ fatal_perror("%s: can't open device file %s",st->nl.name,
+ st->device_path);
+ }
+ memset(&ifr,0,sizeof(ifr));
+ ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Just send/receive IP packets,
+ no extra headers */
+ if (st->interface_name)
+ strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
+ if (ioctl(st->fd,TUNSETIFF,&ifr)<0) {
+ fatal_perror("%s: ioctl(TUNSETIFF)",st->nl.name);
+ }
+ if (!st->interface_name) {
+ st->interface_name=safe_malloc(strlen(ifr.ifr_name)+1,"tun_apply");
+ strcpy(st->interface_name,ifr.ifr_name);
+ Message(M_INFO,"%s: allocated network interface %s\n",st->nl.name,
+ st->interface_name);
}
- return;
+ add_hook(PHASE_DROPPRIV,tun_phase_hook,st);
+
+ return new_closure(&st->nl.cl);
}
+#endif /* HAVE_LINUX_IF_H */
-static list_t *userv_apply(closure_t *self, struct cloc loc, dict_t *context,
- list_t *args)
+static list_t *tun_old_apply(closure_t *self, struct cloc loc, dict_t *context,
+ list_t *args)
{
- struct userv *st;
+ struct tun *st;
item_t *item;
dict_t *dict;
+ bool_t search_for_if;
- st=safe_malloc(sizeof(*st),"userv_apply (netlink)");
- st->cl.description="userv-netlink";
- st->cl.type=CL_NETLINK;
- st->cl.apply=NULL;
- st->cl.interface=&st->ops;
- st->ops.st=st;
- st->ops.regnets=userv_regnets;
- st->ops.deliver=userv_deliver;
- st->max_start_pad=0;
- st->max_end_pad=0;
- st->rxfd=-1; st->txfd=-1;
- st->clients=NULL;
+ st=safe_malloc(sizeof(*st),"tun_old_apply");
+
+ Message(M_WARNING,"the tun-old code has never been tested. Please report "
+ "success or failure to steve@greenend.org.uk\n");
/* First parameter must be a dict */
item=list_elem(args,0);
if (!item || item->type!=t_dict)
- cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n");
+ cfgfatal(loc,"tun","parameter must be a dictionary\n");
dict=item->data.dict;
- st->name=dict_read_string(dict,"name",False,"userv-netlink",loc);
- st->userv_path=dict_read_string(dict,"userv-path",False,"userv-netlink",
- loc);
- st->service_user=dict_read_string(dict,"service-user",False,
- "userv-netlink",loc);
- st->service_name=dict_read_string(dict,"service-name",False,
- "userv-netlink",loc);
- if (!st->name) st->name="netlink-userv-ipif";
- if (!st->userv_path) st->userv_path="userv";
- if (!st->service_user) st->service_user="root";
- if (!st->service_name) st->service_name="ipif";
- dict_read_subnet_list(dict, "networks", True, "userv-netlink", loc,
- &st->networks);
- st->local_address=string_to_ipaddr(
- dict_find_item(dict,"local-address", True, "userv-netlink", loc),
- "userv-netlink");
- st->secnet_address=string_to_ipaddr(
- dict_find_item(dict,"secnet-address", True, "userv-netlink", loc),
- "userv-netlink");
- if (!subnet_match(&st->networks,st->local_address)) {
- cfgfatal(loc,"netlink-userv-ipif","local-address must be in "
- "local networks\n");
+
+ st->netlink_to_tunnel=
+ netlink_init(&st->nl,st,loc,dict,
+ "netlink-tun",tun_deliver_to_kernel);
+
+ st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
+ st->interface_name=dict_read_string(dict,"interface",False,
+ "tun-netlink",loc);
+ search_for_if=dict_read_bool(dict,"interface-search",False,"tun-netlink",
+ loc,st->device_path==NULL);
+ st->ifconfig_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
+ st->route_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
+
+ if (!st->device_path) st->device_path="/dev/tun";
+ if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
+ if (!st->route_path) st->route_path="route";
+ st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
+
+ /* Old TUN interface: the network interface name depends on which
+ /dev/tunX file we open. If 'interface-search' is set to true, treat
+ 'device' as the prefix and try numbers from 0--255. If it's set
+ to false, treat 'device' as the whole name, and require than an
+ appropriate interface name be specified. */
+ if (search_for_if) {
+ string_t dname;
+ int i;
+
+ if (st->interface_name) {
+ cfgfatal(loc,"tun-old","you may not specify an interface name "
+ "in interface-search mode\n");
+ }
+ dname=safe_malloc(strlen(st->device_path)+4,"tun_old_apply");
+ st->interface_name=safe_malloc(8,"tun_old_apply");
+
+ for (i=0; i<255; i++) {
+ sprintf(dname,"%s%d",st->device_path,i);
+ if ((st->fd=open(dname,O_RDWR))>0) {
+ sprintf(st->interface_name,"tun%d",i);
+ Message(M_INFO,"%s: allocated network interface %s "
+ "through %s\n",st->nl.name,st->interface_name,dname);
+ continue;
+ }
+ }
+ if (st->fd==-1) {
+ fatal("%s: unable to open any TUN device (%s...)\n",
+ st->nl.name,st->device_path);
+ }
+ } else {
+ if (!st->interface_name) {
+ cfgfatal(loc,"tun-old","you must specify an interface name "
+ "when you explicitly specify a TUN device file\n");
+ }
+ st->fd=open(st->device_path,O_RDWR);
+ if (st->fd==-1) {
+ fatal_perror("%s: unable to open TUN device file %s",
+ st->nl.name,st->device_path);
+ }
}
- st->mtu=dict_read_number(dict, "mtu", False, "userv-netlink", loc, 1000);
- st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"userv-netlink",loc);
- BUF_ALLOC(st->buff,"netlink:userv_apply");
- add_hook(PHASE_DROPPRIV,userv_phase_hook,st);
+ add_hook(PHASE_DROPPRIV,tun_phase_hook,st);
- return new_closure(&st->cl);
+ return new_closure(&st->nl.cl);
}
+/* No connection to the kernel at all... */
+
struct null {
- closure_t cl;
- struct netlink_if ops;
+ struct netlink nl;
};
-static void *null_regnets(void *sst, struct subnet_list *nets,
- netlink_deliver_fn *deliver, void *dst,
- uint32_t max_start_pad, uint32_t max_end_pad)
-{
- Message(M_DEBUG_CONFIG,"null_regnets: request for %d networks, "
- "max_start_pad=%d, max_end_pad=%d\n",
- nets->entries,max_start_pad,max_end_pad);
- return NULL;
-}
-
static void null_deliver(void *sst, void *cid, struct buffer_if *buf)
{
return;
list_t *args)
{
struct null *st;
+ item_t *item;
+ dict_t *dict;
- st=safe_malloc(sizeof(*st),"null_apply (netlink)");
- st->cl.description="null-netlink";
- st->cl.type=CL_NETLINK;
- st->cl.apply=NULL;
- st->cl.interface=&st->ops;
- st->ops.st=st;
- st->ops.regnets=null_regnets;
- st->ops.deliver=null_deliver;
+ st=safe_malloc(sizeof(*st),"null_apply");
- return new_closure(&st->cl);
+ item=list_elem(args,0);
+ if (!item || item->type!=t_dict)
+ cfgfatal(loc,"null-netlink","parameter must be a dictionary\n");
+
+ dict=item->data.dict;
+
+ netlink_init(&st->nl,st,loc,dict,"null-netlink",null_deliver);
+
+ return new_closure(&st->nl.cl);
}
init_module netlink_module;
void netlink_module(dict_t *dict)
{
add_closure(dict,"userv-ipif",userv_apply);
+#ifdef HAVE_LINUX_IF_H
+ add_closure(dict,"tun",tun_apply);
+#endif
+ add_closure(dict,"tun-old",tun_old_apply);
+ add_closure(dict,"null-netlink",null_apply);
#if 0
+ /* TODO */
add_closure(dict,"pty-slip",ptyslip_apply);
add_closure(dict,"slipd",slipd_apply);
#endif /* 0 */
- add_closure(dict,"null-netlink",null_apply);
}