tinc 1.0.37 with macOS feth device support
This commit is contained in:
commit
b668b14a74
127 changed files with 64704 additions and 0 deletions
27
AUTHORS
Normal file
27
AUTHORS
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
Main tinc authors:
|
||||
- Guus Sliepen <guus@tinc-vpn.org>
|
||||
- Ivo Timmermans (inactive)
|
||||
|
||||
Significant contributions from:
|
||||
- Michael Tokarev <mjt@tls.msk.ru>
|
||||
- Florian Forster <octo@verplant.org>
|
||||
- Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||
- Max Rijevski <maksuf@gmail.com>
|
||||
- Scott Lamb <slamb@slamb.org>
|
||||
- Julien Muchembled <jm@jmuchemb.eu>
|
||||
- Timothy Redaelli <timothy@redaelli.eu>
|
||||
- Brandon Black <blblack@gmail.com>
|
||||
- Loïc Grenié <loic.grenie@gmail.com>
|
||||
|
||||
These files are from other sources:
|
||||
* lib/pidfile.h and lib/pidfile.c are by Martin Schulze, taken from
|
||||
the syslog 1.3 sources.
|
||||
|
||||
* src/bsd/tunemu.c and tunemu.h are by Friedrich Schöller
|
||||
<friedrich.schoeller@gmail.com>
|
||||
|
||||
Also some of the macro files in the directory m4, and their
|
||||
accompanying files in lib, were taken from GNU fileutils.
|
||||
|
||||
Please see the file THANKS for more information on contributions from
|
||||
users.
|
||||
289
COPYING
Normal file
289
COPYING
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
Copyright (C) 1998-2026 Ivo Timmermans, Guus Sliepen and others.
|
||||
See the AUTHORS file for a complete list.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
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
|
||||
19
COPYING.README
Normal file
19
COPYING.README
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
The following applies to tinc:
|
||||
|
||||
This program is released under the GPL with the additional exemption that
|
||||
compiling, linking, and/or using OpenSSL is allowed. You may provide binary
|
||||
packages linked to the OpenSSL libraries, provided that all other requirements
|
||||
of the GPL are met.
|
||||
|
||||
The following applies to the LZO library:
|
||||
|
||||
Hereby I grant a special exception to the tinc VPN project
|
||||
(http://tinc.nl.linux.org/) to link the LZO library with the OpenSSL library
|
||||
(http://www.openssl.org).
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
|
||||
When tinc is compiled with the --enable-tunemu option, the resulting binary
|
||||
falls under the GPL version 3 or later.
|
||||
|
||||
|
||||
380
INSTALL
Normal file
380
INSTALL
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
The following shell commands:
|
||||
|
||||
test -f configure || ./bootstrap
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
should configure, build, and install this package. The first line,
|
||||
which bootstraps, is intended for developers; when building from
|
||||
distribution tarballs it does nothing and can be skipped. A package
|
||||
might name the bootstrapping script differently; if the name is
|
||||
‘autogen.sh’, for example, the first line should say ‘./autogen.sh’
|
||||
instead of ‘./bootstrap’.
|
||||
|
||||
The following more-detailed instructions are generic; see the
|
||||
‘README’ file for instructions specific to this package. Some packages
|
||||
provide this ‘INSTALL’ file but do not implement all of the features
|
||||
documented below. The lack of an optional feature in a given package is
|
||||
not necessarily a bug. More recommendations for GNU packages can be
|
||||
found in the GNU Coding Standards.
|
||||
|
||||
Many packages have scripts meant for developers instead of ordinary
|
||||
builders, as they may use developer tools that are less commonly
|
||||
installed, or they may access the network, which has privacy
|
||||
implications. These scripts attempt to bootstrap by building the
|
||||
‘configure’ script and related files, possibly using developer tools or
|
||||
the network. Because the output of bootstrapping is system-independent,
|
||||
it is normally run by a package developer so that its output can be put
|
||||
into the distribution tarball and ordinary builders and users need not
|
||||
bootstrap. Some packages have commands like ‘./autopull.sh’ and
|
||||
‘./autogen.sh’ that you can run instead of ‘./bootstrap’, for more
|
||||
fine-grained control over bootstrapping.
|
||||
|
||||
The ‘configure’ script attempts to guess correct values for various
|
||||
system-dependent variables used during compilation. It uses those
|
||||
values to create a ‘Makefile’ in each directory of the package. It may
|
||||
also create one or more ‘.h’ files containing system-dependent
|
||||
definitions. Finally, it creates a script ‘config.status’ that you can
|
||||
run in the future to recreate the current configuration, and a file
|
||||
‘config.log’ containing output useful for debugging ‘configure’.
|
||||
|
||||
It can also use an optional file (typically called ‘config.cache’ and
|
||||
enabled with ‘--cache-file=config.cache’ or simply ‘-C’) that saves the
|
||||
results of its tests to speed up reconfiguring. Caching is disabled by
|
||||
default to prevent problems with accidental use of stale cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how ‘configure’ could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the ‘README’ so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point ‘config.cache’ contains results you don’t want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The ‘autoconf’ program generates ‘configure’ from the file
|
||||
‘configure.ac’. Normally you should edit ‘configure.ac’ instead of
|
||||
editing ‘configure’ directly.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. ‘cd’ to the directory containing the package’s source code.
|
||||
|
||||
2. If this is a developer checkout and file ‘configure’ does not yet
|
||||
exist, run the bootstrapping script (typically ‘./bootstrap’ or
|
||||
‘./autogen.sh’) to bootstrap and create the file. You may need
|
||||
special developer tools and network access to bootstrap, and the
|
||||
network access may have privacy implications.
|
||||
|
||||
3. Type ‘./configure’ to configure the package for your system. This
|
||||
might take a while. While running, ‘configure’ prints messages
|
||||
telling which features it is checking for.
|
||||
|
||||
4. Type ‘make’ to compile the package.
|
||||
|
||||
5. Optionally, type ‘make check’ to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
|
||||
6. Type ‘make install’ to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the ‘make install’ phase executed with root
|
||||
privileges.
|
||||
|
||||
7. Optionally, type ‘make installcheck’ to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior ‘make install’ required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
8. You can remove the program binaries and object files from the
|
||||
source code directory by typing ‘make clean’. To also remove the
|
||||
files that ‘configure’ created (so you can compile the package for
|
||||
a different kind of computer), type ‘make distclean’. There is
|
||||
also a ‘make maintainer-clean’ target, but that is intended mainly
|
||||
for the package’s developers. If you use it, you may have to
|
||||
bootstrap again.
|
||||
|
||||
9. If the package follows the GNU Coding Standards, you can type ‘make
|
||||
uninstall’ to remove the installed files.
|
||||
|
||||
Installation Prerequisites
|
||||
==========================
|
||||
|
||||
Installation requires a POSIX-like environment with a shell and at
|
||||
least the following standard utilities:
|
||||
|
||||
awk cat cp diff echo expr false ls mkdir mv printf pwd rm rmdir sed
|
||||
sort test tr
|
||||
|
||||
This package’s installation may need other standard utilities such as
|
||||
‘grep’, ‘make’, ‘sleep’ and ‘touch’, along with compilers like ‘gcc’.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the ‘configure’ script does not know about. Run ‘./configure --help’
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give ‘configure’ initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here is
|
||||
an example:
|
||||
|
||||
./configure CC=gcc CFLAGS=-g LIBS=-lposix
|
||||
|
||||
See “Defining Variables” for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each system in their own
|
||||
directory. To do this, you can use GNU ‘make’. ‘cd’ to the directory
|
||||
where you want the object files and executables to go and run the
|
||||
‘configure’ script. ‘configure’ automatically checks for the source
|
||||
code in the directory that ‘configure’ is in and in ‘..’. This is known
|
||||
as a “VPATH” build.
|
||||
|
||||
With a non-GNU ‘make’, it is safer to compile the package for one
|
||||
system at a time in the source code directory. After you have installed
|
||||
the package for one system, use ‘make distclean’ before reconfiguring
|
||||
for another system.
|
||||
|
||||
Some platforms, notably macOS, support “fat” or “universal” binaries,
|
||||
where a single binary can execute on different architectures. On these
|
||||
platforms you can configure and compile just once, with options specific
|
||||
to that platform.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, ‘make install’ installs the package’s commands under
|
||||
‘/usr/local/bin’, include files under ‘/usr/local/include’, etc. You
|
||||
can specify an installation prefix other than ‘/usr/local’ by giving
|
||||
‘configure’ the option ‘--prefix=PREFIX’, where PREFIX must be an
|
||||
absolute file name.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option ‘--exec-prefix=PREFIX’ to ‘configure’, the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like ‘--bindir=DIR’ to specify different values for particular
|
||||
kinds of files. Run ‘configure --help’ for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the default
|
||||
for these options is expressed in terms of ‘${prefix}’, so that
|
||||
specifying just ‘--prefix’ will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to ‘configure’; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
‘make install’ command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, ‘make install
|
||||
prefix=/alternate/directory’ will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
‘${prefix}’. Any directories that were specified during ‘configure’,
|
||||
but not in terms of ‘${prefix}’, must each be overridden at install time
|
||||
for the entire installation to be relocated. The approach of makefile
|
||||
variable overrides for each directory variable is required by the GNU
|
||||
Coding Standards, and ideally causes no recompilation. However, some
|
||||
platforms have known limitations with the semantics of shared libraries
|
||||
that end up requiring recompilation when using this method, particularly
|
||||
noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the ‘DESTDIR’ variable. For
|
||||
example, ‘make install DESTDIR=/alternate/directory’ will prepend
|
||||
‘/alternate/directory’ before all installation names. The approach of
|
||||
‘DESTDIR’ overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of ‘${prefix}’
|
||||
at ‘configure’ time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving ‘configure’ the
|
||||
option ‘--program-prefix=PREFIX’ or ‘--program-suffix=SUFFIX’.
|
||||
|
||||
Some packages pay attention to ‘--enable-FEATURE’ and
|
||||
‘--disable-FEATURE’ options to ‘configure’, where FEATURE indicates an
|
||||
optional part of the package. They may also pay attention to
|
||||
‘--with-PACKAGE’ and ‘--without-PACKAGE’ options, where PACKAGE is
|
||||
something like ‘gnu-ld’. ‘./configure --help’ should mention the
|
||||
‘--enable-...’ and ‘--with-...’ options that the package recognizes.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of ‘make’ will be. For these packages, running ‘./configure
|
||||
--enable-silent-rules’ sets the default to minimal output, which can be
|
||||
overridden with ‘make V=1’; while running ‘./configure
|
||||
--disable-silent-rules’ sets the default to verbose, which can be
|
||||
overridden with ‘make V=0’.
|
||||
|
||||
Specifying a System Type
|
||||
========================
|
||||
|
||||
By default ‘configure’ builds for the current system. To create
|
||||
binaries that can run on a different system type, specify a
|
||||
‘--host=TYPE’ option along with compiler variables that specify how to
|
||||
generate object code for TYPE. For example, to create binaries intended
|
||||
to run on a 64-bit ARM processor:
|
||||
|
||||
./configure --host=aarch64-linux-gnu \
|
||||
CC=aarch64-linux-gnu-gcc \
|
||||
CXX=aarch64-linux-gnu-g++
|
||||
|
||||
If done on a machine that can execute these binaries (e.g., via
|
||||
‘qemu-aarch64’, ‘$QEMU_LD_PREFIX’, and Linux’s ‘binfmt_misc’
|
||||
capability), the build behaves like a native build. Otherwise it is a
|
||||
cross-build: ‘configure’ will make cross-compilation guesses instead of
|
||||
running test programs, and ‘make check’ will not work.
|
||||
|
||||
A system type can either be a short name like ‘mingw64’, or a
|
||||
canonical name like ‘x86_64-pc-linux-gnu’. Canonical names have the
|
||||
form CPU-COMPANY-SYSTEM where SYSTEM is either OS or KERNEL-OS. To
|
||||
canonicalize and validate a system type, you can run the command
|
||||
‘config.sub’, which is often squirreled away in a subdirectory like
|
||||
‘build-aux’. For example:
|
||||
|
||||
$ build-aux/config.sub arm64-linux
|
||||
aarch64-unknown-linux-gnu
|
||||
$ build-aux/config.sub riscv-lnx
|
||||
Invalid configuration 'riscv-lnx': OS 'lnx' not recognized
|
||||
|
||||
You can look at the ‘config.sub’ file to see which types are recognized.
|
||||
If the file is absent, this package does not need the system type.
|
||||
|
||||
If ‘configure’ fails with the diagnostic “cannot guess build type”.
|
||||
‘config.sub’ did not recognize your system’s type. In this case, first
|
||||
fetch the newest versions of these files from the GNU config package
|
||||
(https://savannah.gnu.org/projects/config). If that fixes things,
|
||||
please report it to the maintainers of the package containing
|
||||
‘configure’. Otherwise, you can try the configure option ‘--build=TYPE’
|
||||
where TYPE comes close to your system type; also, please report the
|
||||
problem to <config-patches@gnu.org>.
|
||||
|
||||
For more details about configuring system types, see the Autoconf
|
||||
documentation.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for ‘configure’ scripts to share,
|
||||
you can create a site shell script called ‘config.site’ that gives
|
||||
default values for variables like ‘CC’, ‘cache_file’, and ‘prefix’.
|
||||
‘configure’ looks for ‘PREFIX/share/config.site’ if it exists, then
|
||||
‘PREFIX/etc/config.site’ if it exists. Or, you can set the
|
||||
‘CONFIG_SITE’ environment variable to the location of the site script.
|
||||
A warning: not all ‘configure’ scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to ‘configure’. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the ‘configure’ command line, using ‘VAR=value’. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified ‘gcc’ to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for ‘CONFIG_SHELL’ due to an
|
||||
Autoconf limitation. Until the limitation is lifted, you can use this
|
||||
workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
‘configure’ Invocation
|
||||
======================
|
||||
|
||||
‘configure’ recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
‘--help’
|
||||
‘-h’
|
||||
Print a summary of all of the options to ‘configure’, and exit.
|
||||
|
||||
‘--help=short’
|
||||
‘--help=recursive’
|
||||
Print a summary of the options unique to this package’s
|
||||
‘configure’, and exit. The ‘short’ variant lists options used only
|
||||
in the top level, while the ‘recursive’ variant lists options also
|
||||
present in any nested packages.
|
||||
|
||||
‘--version’
|
||||
‘-V’
|
||||
Print the version of Autoconf used to generate the ‘configure’
|
||||
script, and exit.
|
||||
|
||||
‘--cache-file=FILE’
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally ‘config.cache’. FILE defaults to ‘/dev/null’ to
|
||||
disable caching.
|
||||
|
||||
‘--config-cache’
|
||||
‘-C’
|
||||
Alias for ‘--cache-file=config.cache’.
|
||||
|
||||
‘--srcdir=DIR’
|
||||
Look for the package’s source code in directory DIR. Usually
|
||||
‘configure’ can determine that directory automatically.
|
||||
|
||||
‘--prefix=DIR’
|
||||
Use DIR as the installation prefix. See “Installation Names” for
|
||||
more details, including other options available for fine-tuning the
|
||||
installation locations.
|
||||
|
||||
‘--host=TYPE’
|
||||
Build binaries for system TYPE. See “Specifying a System Type”.
|
||||
|
||||
‘--enable-FEATURE’
|
||||
‘--disable-FEATURE’
|
||||
Enable or disable the optional FEATURE. See “Optional Features”.
|
||||
|
||||
‘--with-PACKAGE’
|
||||
‘--without-PACKAGE’
|
||||
Use or omit PACKAGE when building. See “Optional Features”.
|
||||
|
||||
‘--quiet’
|
||||
‘--silent’
|
||||
‘-q’
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to ‘/dev/null’ (any error
|
||||
messages will still be shown).
|
||||
|
||||
‘--no-create’
|
||||
‘-n’
|
||||
Run the configure checks, but stop before creating any output
|
||||
files.
|
||||
|
||||
‘configure’ also recognizes several environment variables, and accepts
|
||||
some other, less widely useful, options. Run ‘configure --help’ for
|
||||
more details.
|
||||
|
||||
Copyright notice
|
||||
================
|
||||
|
||||
Copyright © 1994–1996, 1999–2002, 2004–2017, 2020–2025 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
15
Makefile.am
Normal file
15
Makefile.am
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
## Process this file with automake to get Makefile.in
|
||||
|
||||
AUTOMAKE_OPTIONS = gnu
|
||||
|
||||
SUBDIRS = src doc systemd
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
EXTRA_DIST = COPYING.README README.android
|
||||
|
||||
ChangeLog:
|
||||
git log > ChangeLog
|
||||
|
||||
astyle:
|
||||
astyle --options=.astylerc -nQ src/*.[ch] src/*/*.[ch]
|
||||
826
Makefile.in
Normal file
826
Makefile.in
Normal file
|
|
@ -0,0 +1,826 @@
|
|||
# Makefile.in generated by automake 1.18.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2025 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
am__rm_f = rm -f $(am__rm_f_notfound)
|
||||
am__rm_rf = rm -rf $(am__rm_f_notfound)
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = .
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/ax_append_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
|
||||
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_check_link_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_require_defined.m4 $(top_srcdir)/m4/lzo.m4 \
|
||||
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
|
||||
$(am__configure_deps) $(am__DIST_COMMON)
|
||||
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
|
||||
configure.lineno config.status.lineno
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
|
||||
ctags-recursive dvi-recursive html-recursive info-recursive \
|
||||
install-data-recursive install-dvi-recursive \
|
||||
install-exec-recursive install-html-recursive \
|
||||
install-info-recursive install-pdf-recursive \
|
||||
install-ps-recursive install-recursive installcheck-recursive \
|
||||
installdirs-recursive pdf-recursive ps-recursive \
|
||||
tags-recursive uninstall-recursive
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
am__recursive_targets = \
|
||||
$(RECURSIVE_TARGETS) \
|
||||
$(RECURSIVE_CLEAN_TARGETS) \
|
||||
$(am__extra_recursive_targets)
|
||||
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
|
||||
cscope distdir distdir-am dist dist-all distcheck
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \
|
||||
config.h.in
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
DIST_SUBDIRS = $(SUBDIRS)
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in AUTHORS \
|
||||
COPYING ChangeLog INSTALL NEWS README THANKS compile \
|
||||
config.guess config.sub depcomp install-sh missing
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
distdir = $(PACKAGE)-$(VERSION)
|
||||
top_distdir = $(distdir)
|
||||
am__remove_distdir = \
|
||||
if test -d "$(distdir)"; then \
|
||||
find "$(distdir)" -type d ! -perm -700 -exec chmod u+rwx {} ';' \
|
||||
; rm -rf "$(distdir)" \
|
||||
|| { sleep 5 && rm -rf "$(distdir)"; }; \
|
||||
else :; fi
|
||||
am__post_remove_distdir = $(am__remove_distdir)
|
||||
am__relativize = \
|
||||
dir0=`pwd`; \
|
||||
sed_first='s,^\([^/]*\)/.*$$,\1,'; \
|
||||
sed_rest='s,^[^/]*/*,,'; \
|
||||
sed_last='s,^.*/\([^/]*\)$$,\1,'; \
|
||||
sed_butlast='s,/*[^/]*$$,,'; \
|
||||
while test -n "$$dir1"; do \
|
||||
first=`echo "$$dir1" | sed -e "$$sed_first"`; \
|
||||
if test "$$first" != "."; then \
|
||||
if test "$$first" = ".."; then \
|
||||
dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
|
||||
dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
|
||||
else \
|
||||
first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
|
||||
if test "$$first2" = "$$first"; then \
|
||||
dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
|
||||
else \
|
||||
dir2="../$$dir2"; \
|
||||
fi; \
|
||||
dir0="$$dir0"/"$$first"; \
|
||||
fi; \
|
||||
fi; \
|
||||
dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
|
||||
done; \
|
||||
reldir="$$dir2"
|
||||
DIST_ARCHIVES = $(distdir).tar.gz
|
||||
GZIP_ENV = -9
|
||||
DIST_TARGETS = dist-gzip
|
||||
# Exists only to be overridden by the user if desired.
|
||||
AM_DISTCHECK_DVI_TARGET = dvi
|
||||
distuninstallcheck_listfiles = find . -type f -print
|
||||
am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
|
||||
| sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
|
||||
distcleancheck_listfiles = \
|
||||
find . \( -type f -a \! \
|
||||
\( -name .nfs* -o -name .smb* -o -name .__afs* \) \) -print
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CSCOPE = @CSCOPE@
|
||||
CTAGS = @CTAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
ETAGS = @ETAGS@
|
||||
EXEEXT = @EXEEXT@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
OBJEXT = @OBJEXT@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__rm_f_notfound = @am__rm_f_notfound@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
am__xargs_n = @am__xargs_n@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
systemd_path = @systemd_path@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AUTOMAKE_OPTIONS = gnu
|
||||
SUBDIRS = src doc systemd
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = COPYING.README README.android
|
||||
all: config.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||
|
||||
.SUFFIXES:
|
||||
am--refresh: Makefile
|
||||
@:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
|
||||
$(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
echo ' $(SHELL) ./config.status'; \
|
||||
$(SHELL) ./config.status;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
$(am__cd) $(srcdir) && $(AUTOCONF)
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
config.h: stamp-h1
|
||||
@test -f $@ || rm -f stamp-h1
|
||||
@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
|
||||
|
||||
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
|
||||
$(AM_V_at)rm -f stamp-h1
|
||||
$(AM_V_GEN)cd $(top_builddir) && $(SHELL) ./config.status config.h
|
||||
$(srcdir)/config.h.in: $(am__configure_deps)
|
||||
$(AM_V_GEN)($(am__cd) $(top_srcdir) && $(AUTOHEADER))
|
||||
$(AM_V_at)rm -f stamp-h1
|
||||
$(AM_V_at)touch $@
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f config.h stamp-h1
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run 'make' without going through this Makefile.
|
||||
# To change the values of 'make' variables: instead of editing Makefiles,
|
||||
# (1) if the variable is set in 'config.status', edit 'config.status'
|
||||
# (which will cause the Makefiles to be regenerated when you run 'make');
|
||||
# (2) otherwise, pass the desired values on the 'make' command line.
|
||||
$(am__recursive_targets):
|
||||
@fail=; \
|
||||
if $(am__make_keepgoing); then \
|
||||
failcom='fail=yes'; \
|
||||
else \
|
||||
failcom='exit 1'; \
|
||||
fi; \
|
||||
dot_seen=no; \
|
||||
target=`echo $@ | sed s/-recursive//`; \
|
||||
case "$@" in \
|
||||
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
|
||||
*) list='$(SUBDIRS)' ;; \
|
||||
esac; \
|
||||
for subdir in $$list; do \
|
||||
echo "Making $$target in $$subdir"; \
|
||||
if test "$$subdir" = "."; then \
|
||||
dot_seen=yes; \
|
||||
local_target="$$target-am"; \
|
||||
else \
|
||||
local_target="$$target"; \
|
||||
fi; \
|
||||
($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|
||||
|| eval $$failcom; \
|
||||
done; \
|
||||
if test "$$dot_seen" = "no"; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
|
||||
fi; test -z "$$fail"
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-recursive
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
|
||||
include_option=--etags-include; \
|
||||
empty_fix=.; \
|
||||
else \
|
||||
include_option=--include; \
|
||||
empty_fix=; \
|
||||
fi; \
|
||||
list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
test ! -f $$subdir/TAGS || \
|
||||
set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
|
||||
fi; \
|
||||
done; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-recursive
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscope: cscope.files
|
||||
test ! -s cscope.files \
|
||||
|| $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
|
||||
clean-cscope:
|
||||
-rm -f cscope.files
|
||||
cscope.files: clean-cscope cscopelist
|
||||
cscopelist: cscopelist-recursive
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
|
||||
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@case `sed 15q $(srcdir)/NEWS` in \
|
||||
*"$(VERSION)"*) : ;; \
|
||||
*) \
|
||||
echo "NEWS not updated; not releasing" 1>&2; \
|
||||
exit 1;; \
|
||||
esac
|
||||
$(am__remove_distdir)
|
||||
$(AM_V_at)$(MKDIR_P) "$(distdir)"
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
|
||||
if test "$$subdir" = .; then :; else \
|
||||
$(am__make_dryrun) \
|
||||
|| test -d "$(distdir)/$$subdir" \
|
||||
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|
||||
|| exit 1; \
|
||||
dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
|
||||
$(am__relativize); \
|
||||
new_distdir=$$reldir; \
|
||||
dir1=$$subdir; dir2="$(top_distdir)"; \
|
||||
$(am__relativize); \
|
||||
new_top_distdir=$$reldir; \
|
||||
echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
|
||||
echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
|
||||
($(am__cd) $$subdir && \
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$$new_top_distdir" \
|
||||
distdir="$$new_distdir" \
|
||||
am__remove_distdir=: \
|
||||
am__skip_length_check=: \
|
||||
am__skip_mode_fix=: \
|
||||
distdir) \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
-test -n "$(am__skip_mode_fix)" \
|
||||
|| find "$(distdir)" -type d ! -perm -755 \
|
||||
-exec chmod u+rwx,go+rx {} \; -o \
|
||||
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
|
||||
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|
||||
|| chmod -R a+r "$(distdir)"
|
||||
dist-gzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-bzip3: distdir
|
||||
tardir=$(distdir) && $(am__tar) | bzip3 -c >$(distdir).tar.bz3
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-lzip: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-xz: distdir
|
||||
tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-zstd: distdir
|
||||
tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
@echo WARNING: "Support for distribution archives compressed with" \
|
||||
"legacy program 'compress' is deprecated." >&2
|
||||
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-shar: distdir
|
||||
@echo WARNING: "Support for shar distribution archives is" \
|
||||
"deprecated." >&2
|
||||
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
|
||||
shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist-zip: distdir
|
||||
-rm -f $(distdir).zip
|
||||
zip -rq $(distdir).zip $(distdir)
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
dist dist-all:
|
||||
$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
|
||||
$(am__post_remove_distdir)
|
||||
|
||||
# This target untars the dist file and tries a VPATH configuration. Then
|
||||
# it guarantees that the distribution is self-contained by making another
|
||||
# tarfile.
|
||||
distcheck: dist
|
||||
case '$(DIST_ARCHIVES)' in \
|
||||
*.tar.gz*) \
|
||||
eval GZIP= gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.bz3*) \
|
||||
bzip3 -dc $(distdir).tar.bz3 | $(am__untar) ;;\
|
||||
*.tar.lz*) \
|
||||
lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
|
||||
*.tar.xz*) \
|
||||
xz -dc $(distdir).tar.xz | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
eval GZIP= gzip -dc $(distdir).shar.gz | unshar ;;\
|
||||
*.zip*) \
|
||||
unzip $(distdir).zip ;;\
|
||||
*.tar.zst*) \
|
||||
zstd -dc $(distdir).tar.zst | $(am__untar) ;;\
|
||||
esac
|
||||
chmod -R a-w $(distdir)
|
||||
chmod u+w $(distdir)
|
||||
mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
|
||||
chmod a-w $(distdir)
|
||||
test -d $(distdir)/_build || exit 0; \
|
||||
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
|
||||
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
|
||||
&& am__cwd=`pwd` \
|
||||
&& $(am__cd) $(distdir)/_build/sub \
|
||||
&& ../../configure \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) \
|
||||
$(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
--srcdir=../.. --prefix="$$dc_install_base" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) check \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
|
||||
distuninstallcheck \
|
||||
&& chmod -R a-w "$$dc_install_base" \
|
||||
&& ({ \
|
||||
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
|
||||
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
|
||||
} || { rm -rf "$$dc_destdir"; exit 1; }) \
|
||||
&& rm -rf "$$dc_destdir" \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) dist \
|
||||
&& rm -rf $(DIST_ARCHIVES) \
|
||||
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
|
||||
&& cd "$$am__cwd" \
|
||||
|| exit 1
|
||||
$(am__post_remove_distdir)
|
||||
@(echo "$(distdir) archives ready for distribution: "; \
|
||||
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
|
||||
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
|
||||
distuninstallcheck:
|
||||
@test -n '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: trying to run $@ with an empty' \
|
||||
'$$(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
$(am__cd) '$(distuninstallcheck_dir)' || { \
|
||||
echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
|
||||
exit 1; \
|
||||
}; \
|
||||
test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left after uninstall:" ; \
|
||||
if test -n "$(DESTDIR)"; then \
|
||||
echo " (check DESTDIR support)"; \
|
||||
fi ; \
|
||||
$(distuninstallcheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
distcleancheck: distclean
|
||||
@if test '$(srcdir)' = . ; then \
|
||||
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|
||||
|| { echo "ERROR: files left in build directory after distclean:" ; \
|
||||
$(distcleancheck_listfiles) ; \
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: check-recursive
|
||||
all-am: Makefile config.h
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
install: install-recursive
|
||||
install-exec: install-exec-recursive
|
||||
install-data: install-data-recursive
|
||||
uninstall: uninstall-recursive
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-recursive
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-$(am__rm_f) $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-recursive
|
||||
|
||||
clean-am: clean-generic mostlyclean-am
|
||||
|
||||
distclean: distclean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
|
||||
|
||||
dvi: dvi-recursive
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-recursive
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-recursive
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-recursive
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-recursive
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-recursive
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-recursive
|
||||
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
|
||||
-rm -rf $(top_srcdir)/autom4te.cache
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-recursive
|
||||
|
||||
mostlyclean-am: mostlyclean-generic
|
||||
|
||||
pdf: pdf-recursive
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: $(am__recursive_targets) all install-am install-strip
|
||||
|
||||
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
|
||||
am--refresh check check-am clean clean-cscope clean-generic \
|
||||
cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
|
||||
dist-bzip3 dist-gzip dist-lzip dist-shar dist-tarZ dist-xz \
|
||||
dist-zip dist-zstd distcheck distclean distclean-generic \
|
||||
distclean-hdr distclean-tags distcleancheck distdir \
|
||||
distuninstallcheck dvi dvi-am html html-am info info-am \
|
||||
install install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-pdf install-pdf-am install-ps install-ps-am \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
installdirs-am maintainer-clean maintainer-clean-generic \
|
||||
mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \
|
||||
tags-am uninstall uninstall-am
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
ChangeLog:
|
||||
git log > ChangeLog
|
||||
|
||||
astyle:
|
||||
astyle --options=.astylerc -nQ src/*.[ch] src/*/*.[ch]
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
|
||||
# Tell GNU make to disable its built-in pattern rules.
|
||||
%:: %,v
|
||||
%:: RCS/%,v
|
||||
%:: RCS/%
|
||||
%:: s.%
|
||||
%:: SCCS/s.%
|
||||
766
NEWS
Normal file
766
NEWS
Normal file
|
|
@ -0,0 +1,766 @@
|
|||
Version 1.0.37 March 1 2026
|
||||
|
||||
* Minor fixes.
|
||||
* Drop support for Linux ethertap devices.
|
||||
* Ensure tinc compiles cleanly on modern systems.
|
||||
|
||||
This will most likely be the last version of tinc 1.0.
|
||||
|
||||
Version 1.0.36 August 26 2019
|
||||
|
||||
* Fix compiling tinc with certain versions of the OpenSSL library.
|
||||
* Fix parsing some IPv6 addresses with :: in them.
|
||||
* Fix GraphDumpFile output to handle node names starting with a digit.
|
||||
* Fix a potential segmentation fault when fragmenting packets.
|
||||
|
||||
Thanks to Rosen Penev, Quentin Rameau and Werner Schreiber for their
|
||||
contributions to this version of tinc.
|
||||
|
||||
Version 1.0.35 October 5 2018
|
||||
|
||||
* Prevent oracle attacks (CVE-2018-16737, CVE-2018-16738).
|
||||
* Prevent a MITM from forcing a NULL cipher for UDP (CVE-2018-16758).
|
||||
* Minor fixes in the documentation.
|
||||
|
||||
Thanks to Amine Amri and Rafael Sadowski for their contributions to this
|
||||
version of tinc.
|
||||
|
||||
Version 1.0.34 June 12 2018
|
||||
|
||||
* Fix a potential segmentation fault when connecting to an IPv6 peer via a
|
||||
proxy.
|
||||
* Minor improvements to the build system.
|
||||
* Make the systemd service file identical to the one from the 1.1 branch.
|
||||
* Fix a potential problem causing IPv4 sockets to not work on macOS.
|
||||
|
||||
Thanks to Maximilian Stein and Wang Liu Shuai for their contributions to this
|
||||
version of tinc.
|
||||
|
||||
Version 1.0.33 November 4 2017
|
||||
|
||||
* Allow compilation from a build directory.
|
||||
* Source code cleanups.
|
||||
* Fix some options specified on the command line not surviving a HUP signal.
|
||||
* Handle tun/tap device returning EPERM or EBUSY.
|
||||
* Disable PMTUDiscovery when TCPOnly is used.
|
||||
* Support the --runstatedir option of the autoconf 2.70.
|
||||
|
||||
Thanks to Rafael Sadowski and Pierre-Olivier Mercier for their contributions to
|
||||
this version of tinc.
|
||||
|
||||
Version 1.0.32 September 2 2017
|
||||
|
||||
* Fix segmentation fault when using Cipher = none.
|
||||
* Fix Proxy = exec.
|
||||
* Support PriorityInheritance for IPv6 packets.
|
||||
* Fixes for Solaris tun/tap support.
|
||||
* Bind outgoing TCP sockets when ListenAddress is used.
|
||||
|
||||
Thanks to Vittorio Gambaletta for his contribution to this version of tinc.
|
||||
|
||||
Version 1.0.31 January 15 2017
|
||||
|
||||
* Remove ExecStop in tinc@.service.
|
||||
|
||||
Thanks to Élie Bouttier for his contribution to this version of tinc.
|
||||
|
||||
Version 1.0.30 October 30 2016
|
||||
|
||||
* Fix troubles connecting to some HTTP proxies.
|
||||
|
||||
* Add mitigations for the Sweet32 attack when using a 64-bit block cipher.
|
||||
|
||||
* Use AES256 and SHA256 as the default encryption and digest algorithms.
|
||||
|
||||
Version 1.0.29 October 9 2016
|
||||
|
||||
* Fix UDP communication with peers with link-local IPv6 addresses.
|
||||
|
||||
* Ensure compatibility with OpenSSL 1.1.0.
|
||||
|
||||
* Ensure autoreconf can be run without requiring autoconf-archive.
|
||||
|
||||
* Log warnings about dropped packets only at debug level 5.
|
||||
|
||||
Version 1.0.28 April 10 2016
|
||||
|
||||
* Fix compilation on BSD platforms.
|
||||
|
||||
* Add systemd service files.
|
||||
|
||||
Version 1.0.27 April 10 2016
|
||||
|
||||
* When using Proxy, let the proxy resolve hostnames if tinc can't.
|
||||
|
||||
* Fixes and improvements of the DecrementTTL option.
|
||||
|
||||
* Fixed the $NAME variable in subnet-up/down scripts for the local Subnets.
|
||||
|
||||
* Fixed potentially wrong checksum generation when clamping the MSS.
|
||||
|
||||
* Properly choose between the system's or our own copy of getopt.
|
||||
|
||||
* Fixed compiling tinc for Cygwin with MinGW installed.
|
||||
|
||||
* Added support for OS X utun interfaces.
|
||||
|
||||
* Documentation updates and minor fixes.
|
||||
|
||||
Thanks to Vittorio Gambaletta, LunarShaddow, Florian Weik and Nathan Stratton
|
||||
Treadway for their contributions to this version of tinc.
|
||||
|
||||
Version 1.0.26 July 5 2015
|
||||
|
||||
* Tinc now forces glibc to reload /etc/resolv.conf for every hostname lookup.
|
||||
|
||||
* Fixed --logfile without a filename on Windows.
|
||||
|
||||
* Ensure tinc can be compiled when using musl libc.
|
||||
|
||||
Thanks to Jo-Philipp Wich for his contribution to this version of tinc.
|
||||
|
||||
Version 1.0.25 December 22 2014
|
||||
|
||||
* Documentation updates.
|
||||
|
||||
* Support linking against -lresolv on Mac OS X.
|
||||
|
||||
* Fix scripts on Windows when using the ScriptsInterpreter option.
|
||||
|
||||
* Allow a minimum reconnect timeout to be specified.
|
||||
|
||||
* Support PriorityInheritance on IPv6 sockets.
|
||||
|
||||
Thanks to David Pflug, Baptiste Jonglez, Alexis Hildebrandt, Borg, Jochen Voss,
|
||||
Tomislav Čohar and VittGam for their contributions to this version of tinc.
|
||||
|
||||
Version 1.0.24 May 11 2014
|
||||
|
||||
* Various compiler hardening flags are enabled by default.
|
||||
|
||||
* Updated support for Solaris, allowing switch mode on Solaris 11.
|
||||
|
||||
* Configuration will now also be read from a conf.d directory.
|
||||
|
||||
* Various updates to the documentation.
|
||||
|
||||
* Tinc now forces glibc to reload /etc/resolv.conf after it receives SIGALRM.
|
||||
|
||||
* Fixed a potential routing loop when IndirectData or TCPOnly is used and
|
||||
broadcast packets are being sent.
|
||||
|
||||
* Improved security with constant time memcmp and stricter use of OpenSSL's
|
||||
RNG functions.
|
||||
|
||||
* Fixed all issues found by Coverity.
|
||||
|
||||
Thanks to Florent Clairambault, Vilbrekin, luckyhacky, Armin Fisslthaler, Loïc
|
||||
Dachary and Steffan Karger for their contributions to this version of tinc.
|
||||
|
||||
Version 1.0.23 October 19 2013
|
||||
|
||||
* Start authentication immediately on outgoing connections (useful for sslh).
|
||||
|
||||
* Fixed segfault when Name = $HOST but $HOST is not set.
|
||||
|
||||
* Updated the build system and the documentation.
|
||||
|
||||
* Clean up child processes left over from Proxy = exec.
|
||||
|
||||
Version 1.0.22 August 13 2013
|
||||
|
||||
* Fixed the combination of Mode = router and DeviceType = tap.
|
||||
|
||||
* The $NAME variable is now set in subnet-up/down scripts.
|
||||
|
||||
* Tinc now gives an error when unknown options are given on the command line.
|
||||
|
||||
* Tinc now correctly handles a space between a short command line option and
|
||||
an optional argument.
|
||||
|
||||
Thanks to Etienne Dechamps for his contribution to this version of tinc.
|
||||
|
||||
Version 1.0.21 April 22 2013
|
||||
|
||||
* Drop packets forwarded via TCP if they are too big (CVE-2013-1428).
|
||||
|
||||
Thanks to Martin Schobert for auditing tinc and reporting this vulnerability.
|
||||
|
||||
Version 1.0.20 March 03 2013
|
||||
|
||||
* Use /dev/tap0 by default on FreeBSD and NetBSD when using switch mode.
|
||||
|
||||
* Minor improvements and clarifications in the documentation.
|
||||
|
||||
* Allow tinc to be cross-compiled with Android's NDK.
|
||||
|
||||
* The discovered PMTU is now also applied to VLAN tagged traffic.
|
||||
|
||||
* The LocalDiscovery option now makes use of all addresses tinc is bound to.
|
||||
|
||||
* Fixed support for tunemu on iOS devices.
|
||||
|
||||
* The PriorityInheritance option now also works with switch mode.
|
||||
|
||||
* Fixed tinc crashing when using a SOCKS5 proxy.
|
||||
|
||||
Thanks to Mesar Hameed, Vilbrekin and Martin Schürrer for their contributions
|
||||
to this version of tinc.
|
||||
|
||||
Version 1.0.19 June 25 2012
|
||||
|
||||
* Allow :: notation in IPv6 Subnets.
|
||||
|
||||
* Add support for systemd style socket activation.
|
||||
|
||||
* Allow environment variables to be used for the Name option.
|
||||
|
||||
* Add basic support for SOCKS proxies, HTTP proxies, and proxying through an
|
||||
external command.
|
||||
|
||||
Thanks to Anthony G. Basile and Michael Tokarev for their contributions to
|
||||
this version of tinc.
|
||||
|
||||
Version 1.0.18 March 25 2012
|
||||
|
||||
* Fixed IPv6 in switch mode by turning off DecrementTTL by default.
|
||||
|
||||
* Allow a port number to be specified in BindToAddress, which also allows tinc
|
||||
to listen on multiple ports.
|
||||
|
||||
* Add support for multicast communication with UML/QEMU/KVM.
|
||||
|
||||
Version 1.0.17 March 10 2012
|
||||
|
||||
* The DeviceType option can now be used to select dummy, raw socket, UML and
|
||||
VDE devices without needing to recompile tinc.
|
||||
|
||||
* Allow multiple BindToAddress statements.
|
||||
|
||||
* Decrement TTL value of IPv4 and IPv6 packets.
|
||||
|
||||
* Add LocalDiscovery option allowing tinc to detect peers that are behind the
|
||||
same NAT.
|
||||
|
||||
* Accept Subnets passed with the -o option when StrictSubnets = yes.
|
||||
|
||||
* Disabling old RSA keys when generating new ones now also works properly on
|
||||
Windows.
|
||||
|
||||
Thanks to Nick Hibma for his contribution to this version of tinc.
|
||||
|
||||
Version 1.0.16 July 23 2011
|
||||
|
||||
* Fixed a performance issue with TCP communication under Windows.
|
||||
|
||||
* Fixed code that, during network outages, would cause tinc to exit when it
|
||||
thought two nodes with identical Names were on the VPN.
|
||||
|
||||
Version 1.0.15 June 24 2011
|
||||
|
||||
* Improved logging to file.
|
||||
|
||||
* Reduced amount of process wakeups on platforms which support pselect().
|
||||
|
||||
* Fixed ProcessPriority option under Windows.
|
||||
|
||||
Version 1.0.14 May 8 2011
|
||||
|
||||
* Fixed reading configuration files that do not end with a newline. Again.
|
||||
|
||||
* Allow arbitrary configuration options being specified on the command line.
|
||||
|
||||
* Allow all options in both tinc.conf and the local host config file.
|
||||
|
||||
* Configurable replay window, UDP send and receive buffers for performance tuning.
|
||||
|
||||
* Try harder to get UDP communication back after falling back to TCP.
|
||||
|
||||
* Initial support for attaching tinc to a VDE switch.
|
||||
|
||||
* DragonFly BSD support.
|
||||
|
||||
* Allow linking with OpenSSL 1.0.0.
|
||||
|
||||
Thanks to Brandon Black, Julien Muchembled, Michael Tokarev, Rumko and Timothy
|
||||
Redaelli for their contributions to this version of tinc.
|
||||
|
||||
Version 1.0.13 Apr 11 2010
|
||||
|
||||
* Allow building tinc without LZO and/or Zlib.
|
||||
|
||||
* Clamp MSS of TCP packets in both directions.
|
||||
|
||||
* Experimental StrictSubnets, Forwarding and DirectOnly options,
|
||||
giving more control over information and packets received from/sent to other
|
||||
nodes.
|
||||
|
||||
* Ensure tinc never sends symbolic names for ports over the wire.
|
||||
|
||||
Version 1.0.12 Feb 3 2010
|
||||
|
||||
* Really allow fast roaming of hosts to other nodes in a switched VPN.
|
||||
|
||||
* Fixes missing or incorrect environment variables when calling host-up/down
|
||||
and subnet-up/down scripts in some cases.
|
||||
|
||||
* Allow port to be specified in Address statements.
|
||||
|
||||
* Clamp MSS of TCP packets to the discovered path MTU.
|
||||
|
||||
* Let two nodes behind NAT learn each others current UDP address and port via
|
||||
a third node, potentially allowing direct communications in a similar way to
|
||||
STUN.
|
||||
|
||||
Version 1.0.11 Nov 1 2009
|
||||
|
||||
* Fixed potential crash when the HUP signal is sent.
|
||||
|
||||
* Fixes handling of weighted Subnets in switch and hub modes, preventing
|
||||
unnecessary broadcasts.
|
||||
|
||||
* Works around a MinGW bug that caused packets to Windows nodes to always be
|
||||
sent via TCP.
|
||||
|
||||
* Improvements to the PMTU discovery code, especially on Windows.
|
||||
|
||||
* Use UDP again in certain cases where 1.0.10 was too conservative and fell
|
||||
back to TCP unnecessarily.
|
||||
|
||||
* Allow fast roaming of hosts to other nodes in a switched VPN.
|
||||
|
||||
Version 1.0.10 Oct 18 2009
|
||||
|
||||
* Fixed potential crashes during shutdown and (in rare conditions) when other
|
||||
nodes disconnected from the VPN.
|
||||
|
||||
* Improved NAT handling: tinc now copes with mangled port numbers, and will
|
||||
automatically fall back to TCP if direct UDP connection between nodes is not
|
||||
possible. The TCPOnly option should not have to be used anymore.
|
||||
|
||||
* Allow configuration files with CRLF line endings to be read on UNIX.
|
||||
|
||||
* Disable old RSA keys when generating new ones, and raise the default size of
|
||||
new RSA keys to 2048 bits.
|
||||
|
||||
* Many fixes in the path MTU discovery code, especially when Compression is
|
||||
being used.
|
||||
|
||||
* Tinc can now drop privileges and/or chroot itself.
|
||||
|
||||
* The TunnelServer code now just ignores information from clients instead of
|
||||
disconnecting them.
|
||||
|
||||
* Improved performance on Windows by using the new ProcessPriority option and
|
||||
by making the handling of packets received from the TAP-Win32 adapter more
|
||||
efficient.
|
||||
|
||||
* Code cleanups: tinc now follows the C99 standard, copyright headers have
|
||||
been updated to include patch authors, checkpoint tracing and localisation
|
||||
features have been removed.
|
||||
|
||||
* Support for (jailbroken) iPhone and iPod Touch has been added.
|
||||
|
||||
Thanks to Florian Forster, Grzegorz Dymarek and especially Michael Tokarev for
|
||||
their contributions to this version of tinc.
|
||||
|
||||
Version 1.0.9 Dec 26 2008
|
||||
|
||||
* Fixed tinc as a service under Windows 2003.
|
||||
|
||||
* Fixed reading configuration files that do not end with a newline.
|
||||
|
||||
* Fixed crashes in situations where hostnames could not be resolved or hosts
|
||||
would disconnect at the same time as session keys were exchanged.
|
||||
|
||||
* Improved default settings of tun and tap devices on BSD platforms.
|
||||
|
||||
* Make IPv6 sockets bind only to IPv6 on Linux.
|
||||
|
||||
* Enable path MTU discovery by default.
|
||||
|
||||
* Fixed a memory leak that occurred when connections were closed.
|
||||
|
||||
Thanks to Max Rijevski for his contributions to this version of tinc.
|
||||
|
||||
Version 1.0.8 May 16 2007
|
||||
|
||||
* Fixed some memory and resource leaks.
|
||||
|
||||
* Made network sockets non-blocking under Windows.
|
||||
|
||||
Thanks to Scott Lamb and "dnk" for their contributions to this version of tinc.
|
||||
|
||||
Version 1.0.7 Jan 5 2007
|
||||
|
||||
* Fixed a bug that caused slow network speeds on Windows.
|
||||
|
||||
* Fixed a bug that caused tinc unable to write packets to the tun device on
|
||||
OpenBSD.
|
||||
|
||||
Version 1.0.6 Dec 18 2006
|
||||
|
||||
* More flexible detection of the LZO libraries when compiling.
|
||||
|
||||
* Fixed a bug where broadcasts in switch and hub modes sometimes would not
|
||||
work anymore when part of the VPN had become disconnected from the rest.
|
||||
|
||||
version 1.0.5 Nov 14 2006
|
||||
|
||||
* Lots of small fixes.
|
||||
|
||||
* Broadcast packets no longer grow in size with each hop. This should
|
||||
fix switch mode (again).
|
||||
|
||||
* Generic host-up and host-down scripts.
|
||||
|
||||
* Optionally dump graph in graphviz format to a file or a script.
|
||||
|
||||
* Support LZO 2.0 and later.
|
||||
|
||||
Thanks to Scott Lamb for his contributions to this version of tinc.
|
||||
|
||||
version 1.0.4 May 4 2005
|
||||
|
||||
* Fix switch and hub modes.
|
||||
|
||||
* Optionally start scripts when a Subnet becomes (un)reachable.
|
||||
|
||||
version 1.0.3 Nov 11 2004
|
||||
|
||||
* Show error message when failing to write a PID file.
|
||||
|
||||
* Ignore spaces at end of lines in config files.
|
||||
|
||||
* Fix handling of late packets.
|
||||
|
||||
* Unify BSD tun/tap device handling. This allows IPv6 on tun devices and
|
||||
anything on tap devices as long as the underlying OS supports it.
|
||||
|
||||
* Handle IPv6 on Solaris tun devices.
|
||||
|
||||
* Allow tinc to work properly under Windows XP SP2.
|
||||
|
||||
* Allow VLAN tagged Ethernet frames in switch and hub mode.
|
||||
|
||||
* Experimental PMTUDiscovery, TunnelServer and BlockingTCP options.
|
||||
|
||||
version 1.0.2 Nov 8 2003
|
||||
|
||||
* Fix address and hostname resolving under Windows.
|
||||
|
||||
* Remove warnings about non-existing scripts and unsupported address families.
|
||||
|
||||
* Use the event logger under Windows.
|
||||
|
||||
* Fix quoting of filenames and command line arguments under Windows.
|
||||
|
||||
* Strict checks for length incoming network packets and return values of
|
||||
cryptographic functions,
|
||||
|
||||
* Fix a bug in metadata handling that made the tinc daemon abort.
|
||||
|
||||
version 1.0.1 Aug 14 2003
|
||||
|
||||
* Allow empty lines in config files.
|
||||
|
||||
* Fix handling of spaces and backslashes in filenames under native Windows.
|
||||
|
||||
* Allow scripts to be executed under native Windows.
|
||||
|
||||
* Update documentation, make it less Linux specific.
|
||||
|
||||
version 1.0 Aug 4 2003
|
||||
|
||||
* Lots of small bugfixes and code cleanups.
|
||||
|
||||
* Throughput doubled and latency reduced.
|
||||
|
||||
* Added support for LZO compression.
|
||||
|
||||
* No need to set MAC address or disable ARP anymore.
|
||||
|
||||
* Added support for Windows 2000 and XP, both natively and in a Cygwin
|
||||
environment.
|
||||
|
||||
version 1.0pre8 Sep 16 2002
|
||||
|
||||
* More fixes for subnets with prefixlength undivisible by 8.
|
||||
|
||||
* Added support for NetBSD and MacOS/X.
|
||||
|
||||
* Switched from undirected graphs to directed graphs to avoid certain race
|
||||
conditions and improve scalability.
|
||||
|
||||
* Generalized broadcasting and forwarding of protocol messages.
|
||||
|
||||
* Cleanup of source code.
|
||||
|
||||
|
||||
version 1.0pre7 Apr 7 2002
|
||||
|
||||
* Don't do blocking read()s when getting a signal.
|
||||
|
||||
* Remove RSA key checking code, since it sometimes thinks perfectly good RSA
|
||||
keys are bad.
|
||||
|
||||
* Fix handling of subnets when prefixlength isn't divisible by 8.
|
||||
|
||||
|
||||
version 1.0pre6 Mar 27 2002
|
||||
|
||||
* Improvement of redundant links:
|
||||
|
||||
* Non-blocking connects.
|
||||
|
||||
* Protocol broadcast messages can no longer go into an infinite loop.
|
||||
|
||||
* Graph algorithm updated to look harder for direct connections.
|
||||
|
||||
* Good support for routing IPv6 packets over the VPN. Works on Linux,
|
||||
FreeBSD, possibly OpenBSD but not on Solaris.
|
||||
|
||||
* Support for tunnels over IPv6 networks. Works on all supported
|
||||
operating systems.
|
||||
|
||||
* Optional compression of UDP connections using zlib.
|
||||
|
||||
* Optionally let UDP connections inherit TOS field of tunneled packets.
|
||||
|
||||
* Optionally start scripts when certain hosts become (un)reachable.
|
||||
|
||||
|
||||
version 1.0pre5 Feb 9 2002
|
||||
|
||||
* Security enhancements:
|
||||
|
||||
* Added sequence number and optional message authentication code to
|
||||
the packets.
|
||||
|
||||
* Configurable encryption cipher and digest algorithms.
|
||||
|
||||
* More robust handling of dis- and reconnects.
|
||||
|
||||
* Added a "switch" and a "hub" mode to allow bridging setups.
|
||||
|
||||
* Preliminary support for routing of IPv6 packets.
|
||||
|
||||
* Supports Linux, FreeBSD, OpenBSD and Solaris.
|
||||
|
||||
|
||||
It looks like this might be the last release before 1.0.
|
||||
|
||||
|
||||
version 1.0pre4 Jan 17 2001
|
||||
|
||||
* Updated documentation; the documentation now reflects the
|
||||
configuration as it is.
|
||||
|
||||
* Some internal changes to make tinc scale better for large
|
||||
networks, such as using AVL trees instead of linked lists for the
|
||||
connection list.
|
||||
|
||||
* RSA keys can be stored in separate files if needed. See the
|
||||
documentation for more information.
|
||||
|
||||
* tinc has now been reported to run on Linux PowerPC and FreeBSD x86.
|
||||
|
||||
|
||||
|
||||
version 1.0pre3 Oct 31 2000
|
||||
|
||||
* The protocol has been redesigned, and although some details are
|
||||
still under discussion, this is secure. Care has been taken to
|
||||
resist most, if not all, attacks.
|
||||
|
||||
* Unfortunately this protocol is not compatible with earlier versions,
|
||||
nor are earlier versions compatible with this version. Because the
|
||||
older protocol has huge security flaws, we feel that not
|
||||
implementing backwards compatibility is justified.
|
||||
|
||||
* Some data about the protocol:
|
||||
|
||||
* It uses public/private RSA keys for authentication (this is the
|
||||
actual fix for the security hole).
|
||||
|
||||
* All cryptographic functions have been taken out of tinc, instead
|
||||
it uses the OpenSSL library functions.
|
||||
|
||||
* Offers support for multiple subnets per tinc daemon.
|
||||
|
||||
* New is also the support for the universal tun/tap device. This
|
||||
means better portability to FreeBSD and Solaris.
|
||||
|
||||
* tinc is tested to compile on Solaris, Linux x86, Linux alpha.
|
||||
|
||||
* tinc now uses the OpenSSL library for cryptographic operations.
|
||||
More information on getting and installing OpenSSL is in the manual.
|
||||
This also means that the GMP library is no longer required.
|
||||
|
||||
* Further, thanks to Enrique Zanardi, we have Spanish messages; Matias
|
||||
Carrasco provided us with a Spanish translation of the manual.
|
||||
|
||||
|
||||
What still needs to be done before 1.0:
|
||||
|
||||
* Documentation. Especially since the protocol has changed, and a lot
|
||||
of configuration directives have been added.
|
||||
|
||||
|
||||
|
||||
|
||||
version 1.0pre2 May 31 2000
|
||||
|
||||
* This version has been internationalized; and a Dutch translation has
|
||||
been included.
|
||||
|
||||
* Two configuration variables have been added:
|
||||
* VpnMask - the IP network mask for the entire VPN, not just our
|
||||
subnet (as given by MyVirtualIP). The Redhat and Debian packages
|
||||
use this variable in their system startup scripts, but it is
|
||||
ignored by tinc.
|
||||
* Hostnames - if set to `yes', look up the names of IP addresses
|
||||
trying to connect to us. Default set to `no', to prevent lockups
|
||||
during lookups.
|
||||
|
||||
* The system startup scripts for Debian and Redhat use
|
||||
/etc/tinc/nets.boot to find out which networks need to be started
|
||||
during system boot.
|
||||
|
||||
* Fixes to prevent denial of service attacks by sending random data
|
||||
after connecting (and even when the connection has been established),
|
||||
either random garbage or just nonsensical protocol fields.
|
||||
|
||||
* tinc will retry to connect upon startup, does not quit if it doesn't
|
||||
work the first time.
|
||||
|
||||
* Hosts that are disconnected implicitly if we lose a connection get
|
||||
deleted from the internal list, to prevent hogging eachother with
|
||||
add and delete requests when the connection is restored.
|
||||
|
||||
|
||||
What still needs to be done before 1.0:
|
||||
|
||||
* Documentation.
|
||||
* Failover ConnectTo lines, try another one if the first doesn't work.
|
||||
|
||||
|
||||
|
||||
|
||||
version 1.0pre1 May 12 2000
|
||||
* New meta-protocol
|
||||
* Various other bugfixes
|
||||
* Documentation updates
|
||||
|
||||
version 0.3.3 Feb 9 2000
|
||||
* Fixed bug that made tinc stop working with latest kernels (Guus
|
||||
Sliepen)
|
||||
* Updated the manual
|
||||
|
||||
version 0.3.2 Nov 12 1999
|
||||
* no more `Invalid filedescriptor' when working with multiple
|
||||
connections
|
||||
* forward unknown packets to uplink
|
||||
|
||||
version 0.3.1 Oct 20 1999
|
||||
* fixed a bug where tinc would exit without a trace
|
||||
|
||||
version 0.3 Aug 20 1999
|
||||
* pings now work immediately
|
||||
* all packet sizes get transmitted correctly
|
||||
|
||||
version 0.2.26 Aug 15 1999
|
||||
* fixed some remaining bugs
|
||||
* --sysconfdir works with configure
|
||||
* last version before 0.3
|
||||
|
||||
version 0.2.25 Aug 8 1999
|
||||
* improved stability, going towards 0.3 now.
|
||||
|
||||
version 0.2.24 Aug 7 1999
|
||||
* added key aging, there's a new config variable, KeyExpire.
|
||||
* updated man and info pages
|
||||
|
||||
version 0.2.23 Aug 5 1999
|
||||
* all known bugs fixed, this is a candidate for 0.3
|
||||
|
||||
version 0.2.22 Apr 11 1999
|
||||
* multiconnection thing is now working nearly perfect :)
|
||||
|
||||
version 0.2.21 Apr 10 1999
|
||||
* You shouldn't notice a thing, but a lot has changed wrt key
|
||||
management - except that it refuses to talk to versions < 0.2.20
|
||||
|
||||
version 0.2.20
|
||||
|
||||
version 0.2.19 Apr 3 1999
|
||||
* don't install a libcipher.so
|
||||
|
||||
version 0.2.18 Apr 3 1999
|
||||
* blowfish library dynamically loaded upon execution
|
||||
* included Eric Young's IDEA library
|
||||
|
||||
version 0.2.17 Apr 1 1999
|
||||
* tincd now re-executes itself in case of a segmentation fault.
|
||||
|
||||
version 0.2.16 Apr 1 1999
|
||||
* wrote tincd.conf(5) man page, which still needs a lot of work.
|
||||
* config file now accepts and tolerates spaces, and any integer base
|
||||
for integer variables, and better error reporting. See
|
||||
doc/tincd.conf.sample for an example.
|
||||
|
||||
version 0.2.15 Mar 29 1999
|
||||
* fixed bugs
|
||||
|
||||
version 0.2.14 Feb 10 1999
|
||||
* added --timeout flag and PingTimeout configuration
|
||||
* did some first syslog cleanup work
|
||||
|
||||
version 0.2.13 Jan 23 1999
|
||||
* bugfixes
|
||||
|
||||
version 0.2.12 Jan 23 1999
|
||||
* fixed nauseating bug so that it would crash whenever a connection
|
||||
got lost
|
||||
|
||||
version 0.2.11 Jan 22 1999
|
||||
* framework for multiple connections has been done
|
||||
* simple manpage for tincd
|
||||
|
||||
version 0.2.10 Jan 18 1999
|
||||
* passphrase support added
|
||||
|
||||
version 0.2.9 Jan 13 1999
|
||||
* bugs fixed.
|
||||
|
||||
version 0.2.8 Jan 11 1999
|
||||
* a reworked protocol version
|
||||
* a ping/pong system
|
||||
* more reliable networking code
|
||||
* automatic reconnection
|
||||
* still does not work with more than one connection :)
|
||||
* strips MAC addresses before sending, so there's less overhead, and
|
||||
less redundancy
|
||||
|
||||
version 0.2.7 Jan 3 1999
|
||||
* several updates to make extending more easy.
|
||||
|
||||
version 0.2.6 Dec 20 1998
|
||||
* Point-to-Point connections have been established, including
|
||||
blowfish encryption and a secret key-exchange.
|
||||
|
||||
version 0.2.5 Dec 16 1998
|
||||
* Project renamed to tinc, in honour of TINC.
|
||||
|
||||
version 0.2.4 Dec 16 1998
|
||||
* now it really does ;)
|
||||
|
||||
version 0.2.3 Nov 24 1998
|
||||
* it sort of works now
|
||||
|
||||
version 0.2.2 Nov 20 1998
|
||||
* uses GNU gmp.
|
||||
|
||||
version 0.2.1 Nov 14 1998
|
||||
|
||||
* Bare version.
|
||||
133
README
Normal file
133
README
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
This is the README file for tinc version 1.0.37. Installation
|
||||
instructions may be found in the INSTALL file.
|
||||
|
||||
tinc is Copyright (C) 1998-2026 by:
|
||||
|
||||
Ivo Timmermans,
|
||||
Guus Sliepen <guus@tinc-vpn.org>,
|
||||
and others.
|
||||
|
||||
For a complete list of authors see the AUTHORS file.
|
||||
|
||||
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. See the file COPYING for more details.
|
||||
|
||||
|
||||
Security statement
|
||||
------------------
|
||||
|
||||
In August 2000, we discovered the existence of a security hole in all versions
|
||||
of tinc up to and including 1.0pre2. This had to do with the way we exchanged
|
||||
keys. Since then, we have been working on a new authentication scheme to make
|
||||
tinc as secure as possible. The current version uses the OpenSSL library and
|
||||
uses strong authentication with RSA keys.
|
||||
|
||||
On the 29th of December 2001, Jerome Etienne posted a security analysis of tinc
|
||||
1.0pre4. Due to a lack of sequence numbers and a message authentication code
|
||||
for each packet, an attacker could possibly disrupt certain network services or
|
||||
launch a denial of service attack by replaying intercepted packets. The current
|
||||
version adds sequence numbers and message authentication codes to prevent such
|
||||
attacks.
|
||||
|
||||
On September the 15th of 2003, Peter Gutmann contacted us and showed us a
|
||||
writeup describing various security issues in several VPN daemons. He showed
|
||||
that tinc lacks perfect forward security, the connection authentication could
|
||||
be done more properly, that the sequence number we use as an IV is not the best
|
||||
practice and that the default length of the HMAC for packets is too short in
|
||||
his opinion. We do not know of a way to exploit these weaknesses, but these
|
||||
issues are being addressed in the tinc 1.1 branch.
|
||||
|
||||
The Sweet32 attack affects versions of tinc prior to 1.0.30.
|
||||
|
||||
On September 6th, 2018, Michael Yonly contacted us and provided
|
||||
proof-of-concept code that allowed a remote attacker to create an
|
||||
authenticated, one-way connection with a node, and also that there was a
|
||||
possibility for a man-in-the-middle to force UDP packets from a node to be sent
|
||||
in plaintext. The first issue was trivial to exploit on tinc versions prior to
|
||||
1.0.30, but the changes in 1.0.30 to mitigate the Sweet32 attack made this
|
||||
weakness much harder to exploit. These issues have been fixed in tinc 1.0.35.
|
||||
The new protocol in the tinc 1.1 branch is not susceptible to these issues.
|
||||
|
||||
Cryptography is a hard thing to get right. We cannot make any
|
||||
guarantees. Time, review and feedback are the only things that can
|
||||
prove the security of any cryptographic product. If you wish to review
|
||||
tinc or give us feedback, you are strongly encouraged to do so.
|
||||
|
||||
|
||||
Compatibility
|
||||
-------------
|
||||
|
||||
Version 1.0.37 is compatible with 1.0pre8, 1.0 and later, but not with older
|
||||
versions of tinc. Note that since version 1.0.30, tinc requires all nodes in
|
||||
the VPN to be compiled with a version of LibreSSL or OpenSSL that supports the
|
||||
AES256 and SHA256 algorithms.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
The OpenSSL library is used for all cryptographic functions. You can find it at
|
||||
https://www.openssl.org/. You will need version 1.1.0 or later with support for
|
||||
AES256 and SHA256 enabled. If this library is not installed on your system, the
|
||||
configure script will fail. The manual in doc/tinc.texi contains more detailed
|
||||
information on how to install this library. Alternatively, you may also use the
|
||||
LibreSSL library.
|
||||
|
||||
The zlib library is used for optional compression. You can
|
||||
find it at https://zlib.net/. Because of a possible exploit in
|
||||
earlier versions we recommend that you download version 1.1.4 or later.
|
||||
|
||||
The LZO library is also used for optional compression. You can
|
||||
find it at https://www.oberhumer.com/opensource/lzo/.
|
||||
|
||||
In order to compile tinc, you will need a C99 compliant compiler.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
This version of tinc supports multiple virtual networks at once. To
|
||||
use this feature, you may supply a netname via the -n or --net
|
||||
options. The standard locations for the config files will then be
|
||||
/etc/tinc/<net>/.
|
||||
|
||||
tincd regenerates its encryption key pairs. It does this on the first
|
||||
activity after the keys have expired. This period is adjustable in the
|
||||
configuration file, and the default time is 3600 seconds (one hour).
|
||||
|
||||
This version supports multiple subnets at once. They are also sorted
|
||||
on subnet mask size. This means that it is possible to have
|
||||
overlapping subnets on the VPN, as long as their subnet mask sizes
|
||||
differ.
|
||||
|
||||
Since pre5, tinc can operate in several routing modes. The default mode,
|
||||
"router", works exactly like the older version, and uses Subnet lines to
|
||||
determine the destination of packets. The other two modes, "switch" and "hub",
|
||||
allow the tinc daemons to work together like a single network switch or hub.
|
||||
This is useful for bridging networks. The latter modes only work properly on
|
||||
Linux, FreeBSD and Windows.
|
||||
|
||||
The algorithms used for encryption and generating message authentication codes
|
||||
can now be changed in the configuration files. All cipher and digest algorithms
|
||||
supported by OpenSSL can be used. Useful ciphers are "blowfish" (default),
|
||||
"bf-ofb", "des", "des3", et cetera. Useful digests are "sha1" (default), "md5",
|
||||
et cetera.
|
||||
|
||||
Support for routing IPv6 packets has been added. Just add Subnet lines with
|
||||
IPv6 addresses (without using :: abbreviations) and use ifconfig or ip (from
|
||||
the iproute package) to give the virtual network interface corresponding IPv6
|
||||
addresses. tinc does not provide autoconfiguration for IPv6 hosts. Consider
|
||||
using radvd or zebra if you need it.
|
||||
|
||||
It is also possible to make tunnels to other tinc daemons over IPv6 networks,
|
||||
if the operating system supports IPv6. tinc will automatically use both IPv6
|
||||
and IPv4 when available, but this can be changed by adding the option
|
||||
"AddressFamily = ipv4" or "AddressFamily = ipv6" to the tinc.conf file.
|
||||
|
||||
Normally, when started tinc will detach and run in the background. In a native
|
||||
Windows environment this means tinc will install itself as a service, which will
|
||||
restart after reboots. To prevent tinc from detaching or running as a service,
|
||||
use the -D option.
|
||||
|
||||
25
README.android
Normal file
25
README.android
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Quick how-to cross compile tinc for android (done from $HOME/android/):
|
||||
|
||||
- Download android NDK and setup local ARM toolchain:
|
||||
wget http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86.tar.bz2
|
||||
tar xfj android-ndk-r9d-linux-x86.tar.bz2
|
||||
./android-ndk-r9d/build/tools/make-standalone-toolchain.sh --platform=android-5 --install-dir=/tmp/my-android-toolchain
|
||||
|
||||
- Download and cross-compile openSSL for ARM:
|
||||
wget http://www.openssl.org/source/openssl-1.0.1h.tar.gz
|
||||
tar xfz openssl-1.0.1h.tar.gz
|
||||
cd openssl-1.0.1h
|
||||
./Configure dist
|
||||
make CC=/tmp/my-android-toolchain/bin/arm-linux-androideabi-gcc AR="/tmp/my-android-toolchain/bin/arm-linux-androideabi-ar r" RANLIB=/tmp/my-android-toolchain/bin/arm-linux-androideabi-ranlib
|
||||
cd -
|
||||
|
||||
- Clone and cross-compile tinc:
|
||||
git clone git://tinc-vpn.org/tinc
|
||||
cd tinc
|
||||
autoreconf -fsi
|
||||
CC=/tmp/my-android-toolchain/bin/arm-linux-androideabi-gcc ./configure --host=arm-linux --disable-lzo --with-openssl-lib=$HOME/android/openssl-1.0.1g --with-openssl-include=$HOME/android/openssl-1.0.1g/include/ --disable-hardening
|
||||
make -j5
|
||||
|
||||
- Strip tincd binary to make it smaller
|
||||
/tmp/my-android-toolchain/bin/arm-linux-androideabi-strip src/tincd
|
||||
|
||||
143
THANKS
Normal file
143
THANKS
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
We would like to thank the following people for their contributions to tinc:
|
||||
|
||||
* Alexander Reil and Gemeinde Berg
|
||||
* Alexander Ried
|
||||
* Alexis Hildebrandt
|
||||
* Allesandro Gatti
|
||||
* Andreas van Cranenburgh
|
||||
* Andrew Hahn
|
||||
* Anthony G. Basile
|
||||
* Armijn Hemel
|
||||
* Armin Fisslthaler
|
||||
* Aron Cowan
|
||||
* Ashish Bajaj
|
||||
* Baptiste Jonglez
|
||||
* Big Horn Mountain Log Homes
|
||||
* Borg
|
||||
* Brandon Black
|
||||
* Cheng LI
|
||||
* Cris van Pelt
|
||||
* Darius Jahandarie
|
||||
* Dato Simó
|
||||
* David Pflug
|
||||
* Delf Eldkraft
|
||||
* Delf Ovrahi
|
||||
* Dennis Joachimsthaler
|
||||
* dnk
|
||||
* Егор Палкин
|
||||
* Élie Bouttier
|
||||
* Enrique Zanardi
|
||||
* Erik Tews
|
||||
* Etienne Dechamps
|
||||
* Florent Clairambault
|
||||
* Florian Forster
|
||||
* Florian Klink
|
||||
* Florian Weik
|
||||
* Flynn Marquardt
|
||||
* Franz Pletz
|
||||
* Gabriel Poma
|
||||
* Gary Kessler and Claudia Gonzalez
|
||||
* Grzegorz Dymarek
|
||||
* Gusariev Oleksandr
|
||||
* Hans Bayle
|
||||
* Harvest
|
||||
* Huai An Hsu
|
||||
* Issakov Kirill
|
||||
* Ivan Mirić
|
||||
* Ivo van Dong
|
||||
* Ivo Smits
|
||||
* James Cook
|
||||
* James MacLean
|
||||
* Jamie Briggs
|
||||
* Jan Štembera
|
||||
* Jason Harper
|
||||
* Jason Livesay
|
||||
* Jasper Krijgsman
|
||||
* Jelle de Jong
|
||||
* Jeroen Domburg
|
||||
* Jeroen Ubbink
|
||||
* Jerome Etienne
|
||||
* Jiang Sheng
|
||||
* Jo-Philipp Wich
|
||||
* Jochen Voss
|
||||
* JHS
|
||||
* Julien Muchembled
|
||||
* Lavrans Laading
|
||||
* Loïc Dachary
|
||||
* Loïc Grenié
|
||||
* Lubomír Bulej
|
||||
* luckyhacky
|
||||
* LunarShaddow
|
||||
* Mads Kiilerich
|
||||
* Marc A. Lehmann
|
||||
* Marco Oggioni
|
||||
* Mark Glines
|
||||
* Mark Petryk
|
||||
* Markus Goetz
|
||||
* Martin Kihlgren
|
||||
* Martin Schobert
|
||||
* Martin Schürrer
|
||||
* Martin Weinelt
|
||||
* Matias Carrasco
|
||||
* Max Rijevski
|
||||
* Menno Smits
|
||||
* Mesar Hameed
|
||||
* Michael Taylor
|
||||
* Michael Tokarev
|
||||
* Michael Yonli
|
||||
* Miles Nordin
|
||||
* Nathan Stratton Treadway
|
||||
* Murat Donmez
|
||||
* Nick Hibma
|
||||
* Nick Patavalis
|
||||
* Nils Freydank
|
||||
* Paul Littlefield
|
||||
* Patrick Helms
|
||||
* Pavel Gorin
|
||||
* Philipp Babel
|
||||
* Pierre Emeriaud
|
||||
* Pierre-Olivier Mercier
|
||||
* Rafael Wolf
|
||||
* Rafael Sadowski
|
||||
* Rafał Leśniak
|
||||
* René Rüthlein
|
||||
* Rhosyn Celyn
|
||||
* Robert van der Meulen
|
||||
* Robert Waniek
|
||||
* Rowan Wookey
|
||||
* Rumko
|
||||
* Ryan Miller
|
||||
* Sam Bryan
|
||||
* Samuel Thibault
|
||||
* Saverio Proto
|
||||
* Scott Lamb
|
||||
* Sebastian Lehner
|
||||
* Steffan Karger
|
||||
* Stig Fagrell
|
||||
* Sven-Haegar Koch
|
||||
* Teemu Kiviniemi
|
||||
* Thomas Tsiakalakis
|
||||
* Timothy Redaelli
|
||||
* Tomasz Fortuna
|
||||
* Tomislav Čohar
|
||||
* Tommy Arnkværn
|
||||
* Tonnerre Lombard
|
||||
* Ulrich Seifert
|
||||
* Vil Brekin
|
||||
* Vincent Laurent
|
||||
* Vittorio Gambaletta
|
||||
* Vlatko Kosturjak
|
||||
* Volker Augustin
|
||||
* Wendy Willard
|
||||
* Wessel Dankers
|
||||
* William A. Kennington III
|
||||
* William McArthur
|
||||
* Wouter van Heyst
|
||||
* xentec
|
||||
* 戴 鸣
|
||||
|
||||
And everyone we forgot (if we did, please let us know). Thank you!
|
||||
|
||||
---
|
||||
Ivo Timmermans,
|
||||
Guus Sliepen.
|
||||
1326
aclocal.m4
vendored
Normal file
1326
aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load diff
364
compile
Executable file
364
compile
Executable file
|
|
@ -0,0 +1,364 @@
|
|||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2025-06-18.21; # UTC
|
||||
|
||||
# Copyright (C) 1999-2025 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# 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, 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file unneeded_conversions
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) UNNEEDED_CONVERSIONS, no
|
||||
# conversion will take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
if test -n "$MSYSTEM" && (cygpath --version) >/dev/null 2>&1; then
|
||||
# MSYS2 environment.
|
||||
file_conv=cygwin
|
||||
else
|
||||
# Original MinGW environment.
|
||||
file_conv=mingw
|
||||
fi
|
||||
;;
|
||||
MSYS*)
|
||||
# Old MSYS environment, or MSYS2 with 32-bit MSYS2 shell.
|
||||
file_conv=cygwin
|
||||
;;
|
||||
CYGWIN*)
|
||||
# Cygwin environment.
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
# This is the optimization mentioned above:
|
||||
# If UNNEEDED_CONVERSIONS contains $file_conv, don't convert.
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/*)
|
||||
file=`cygpath -w "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.lo | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
GNU Automake home page: <https://www.gnu.org/software/automake/>.
|
||||
General help using GNU software: <https://www.gnu.org/gethelp/>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile (GNU Automake) $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
|
||||
clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \
|
||||
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp nil t)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%Y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
1815
config.guess
vendored
Executable file
1815
config.guess
vendored
Executable file
File diff suppressed because it is too large
Load diff
491
config.h.in
Normal file
491
config.h.in
Normal file
|
|
@ -0,0 +1,491 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Support for jumbograms (packets up to 9000 bytes) */
|
||||
#undef ENABLE_JUMBOGRAMS
|
||||
|
||||
/* Support for tunemu */
|
||||
#undef ENABLE_TUNEMU
|
||||
|
||||
/* Support for UML */
|
||||
#undef ENABLE_UML
|
||||
|
||||
/* Support for VDE */
|
||||
#undef ENABLE_VDE
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if you have the <arpa/nameser.h> header file. */
|
||||
#undef HAVE_ARPA_NAMESER_H
|
||||
|
||||
/* Define to 1 if you have the 'asprintf' function. */
|
||||
#undef HAVE_ASPRINTF
|
||||
|
||||
/* Unknown BSD variant */
|
||||
#undef HAVE_BSD
|
||||
|
||||
/* Cygwin */
|
||||
#undef HAVE_CYGWIN
|
||||
|
||||
/* Define to 1 if you have the 'daemon' function. */
|
||||
#undef HAVE_DAEMON
|
||||
|
||||
/* Darwin (MacOS/X) */
|
||||
#undef HAVE_DARWIN
|
||||
|
||||
/* Define to 1 if you have the declaration of 'EVP_RSA_gen', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_EVP_RSA_GEN
|
||||
|
||||
/* Define to 1 if you have the declaration of 'freeaddrinfo', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_FREEADDRINFO
|
||||
|
||||
/* Define to 1 if you have the declaration of 'gai_strerror', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_GAI_STRERROR
|
||||
|
||||
/* Define to 1 if you have the declaration of 'getaddrinfo', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_GETADDRINFO
|
||||
|
||||
/* Define to 1 if you have the declaration of 'getnameinfo', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_GETNAMEINFO
|
||||
|
||||
/* Define to 1 if you have the declaration of 'res_init', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_RES_INIT
|
||||
|
||||
/* Define to 1 if you have the 'devname' function. */
|
||||
#undef HAVE_DEVNAME
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* DragonFly */
|
||||
#undef HAVE_DRAGONFLY
|
||||
|
||||
/* Define to 1 if you have the 'fchmod' function. */
|
||||
#undef HAVE_FCHMOD
|
||||
|
||||
/* Define to 1 if you have the 'fdevname' function. */
|
||||
#undef HAVE_FDEVNAME
|
||||
|
||||
/* Define to 1 if you have the 'flock' function. */
|
||||
#undef HAVE_FLOCK
|
||||
|
||||
/* Define to 1 if you have the 'fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* FreeBSD */
|
||||
#undef HAVE_FREEBSD
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
|
||||
/* getopt_long() */
|
||||
#undef HAVE_GETOPT_LONG
|
||||
|
||||
/* Define to 1 if you have the 'gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the 'nsl' library (-lnsl). */
|
||||
#undef HAVE_LIBNSL
|
||||
|
||||
/* Define to 1 if you have the 'resolv' library (-lresolv). */
|
||||
#undef HAVE_LIBRESOLV
|
||||
|
||||
/* Define to 1 if you have the 'socket' library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
|
||||
/* Define to 1 if you have the <libvdeplug_dyn.h> header file. */
|
||||
#undef HAVE_LIBVDEPLUG_DYN_H
|
||||
|
||||
/* Linux */
|
||||
#undef HAVE_LINUX
|
||||
|
||||
/* Define to 1 if you have the <linux/if_tun.h> header file. */
|
||||
#undef HAVE_LINUX_IF_TUN_H
|
||||
|
||||
/* enable lzo compression support */
|
||||
#undef HAVE_LZO
|
||||
|
||||
/* Define to 1 if you have the <lzo1x.h> header file. */
|
||||
#undef HAVE_LZO1X_H
|
||||
|
||||
/* Define to 1 if you have the <lzo2/lzo1x.h> header file. */
|
||||
#undef HAVE_LZO2_LZO1X_H
|
||||
|
||||
/* Define to 1 if you have the <lzo/lzo1x.h> header file. */
|
||||
#undef HAVE_LZO_LZO1X_H
|
||||
|
||||
/* MinGW */
|
||||
#undef HAVE_MINGW
|
||||
|
||||
/* Define to 1 if you have the <minix/config.h> header file. */
|
||||
#undef HAVE_MINIX_CONFIG_H
|
||||
|
||||
/* Define to 1 if you have the 'mlockall' function. */
|
||||
#undef HAVE_MLOCKALL
|
||||
|
||||
/* NetBSD */
|
||||
#undef HAVE_NETBSD
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/icmp6.h> header file. */
|
||||
#undef HAVE_NETINET_ICMP6_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/if_ether.h> header file. */
|
||||
#undef HAVE_NETINET_IF_ETHER_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in6.h> header file. */
|
||||
#undef HAVE_NETINET_IN6_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in_systm.h> header file. */
|
||||
#undef HAVE_NETINET_IN_SYSTM_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/ip6.h> header file. */
|
||||
#undef HAVE_NETINET_IP6_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/ip.h> header file. */
|
||||
#undef HAVE_NETINET_IP_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/ip_icmp.h> header file. */
|
||||
#undef HAVE_NETINET_IP_ICMP_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/tcp.h> header file. */
|
||||
#undef HAVE_NETINET_TCP_H
|
||||
|
||||
/* Define to 1 if you have the <netpacket/packet.h> header file. */
|
||||
#undef HAVE_NETPACKET_PACKET_H
|
||||
|
||||
/* Define to 1 if you have the <net/ethernet.h> header file. */
|
||||
#undef HAVE_NET_ETHERNET_H
|
||||
|
||||
/* Define to 1 if you have the <net/if_arp.h> header file. */
|
||||
#undef HAVE_NET_IF_ARP_H
|
||||
|
||||
/* Define to 1 if you have the <net/if.h> header file. */
|
||||
#undef HAVE_NET_IF_H
|
||||
|
||||
/* Define to 1 if you have the <net/if_tap.h> header file. */
|
||||
#undef HAVE_NET_IF_TAP_H
|
||||
|
||||
/* Define to 1 if you have the <net/if_tun.h> header file. */
|
||||
#undef HAVE_NET_IF_TUN_H
|
||||
|
||||
/* Define to 1 if you have the <net/if_types.h> header file. */
|
||||
#undef HAVE_NET_IF_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <net/if_utun.h> header file. */
|
||||
#undef HAVE_NET_IF_UTUN_H
|
||||
|
||||
/* Define to 1 if you have the <net/tap/if_tap.h> header file. */
|
||||
#undef HAVE_NET_TAP_IF_TAP_H
|
||||
|
||||
/* Define to 1 if you have the <net/tun/if_tun.h> header file. */
|
||||
#undef HAVE_NET_TUN_IF_TUN_H
|
||||
|
||||
/* OpenBSD */
|
||||
#undef HAVE_OPENBSD
|
||||
|
||||
/* enable OpenSSL support */
|
||||
#undef HAVE_OPENSSL
|
||||
|
||||
/* Define to 1 if you have the <openssl/err.h> header file. */
|
||||
#undef HAVE_OPENSSL_ERR_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/evp.h> header file. */
|
||||
#undef HAVE_OPENSSL_EVP_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/param_build.h> header file. */
|
||||
#undef HAVE_OPENSSL_PARAM_BUILD_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/pem.h> header file. */
|
||||
#undef HAVE_OPENSSL_PEM_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/rand.h> header file. */
|
||||
#undef HAVE_OPENSSL_RAND_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/rsa.h> header file. */
|
||||
#undef HAVE_OPENSSL_RSA_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/sha.h> header file. */
|
||||
#undef HAVE_OPENSSL_SHA_H
|
||||
|
||||
/* Define to 1 if you have the 'pselect' function. */
|
||||
#undef HAVE_PSELECT
|
||||
|
||||
/* Define to 1 if you have the 'putenv' function. */
|
||||
#undef HAVE_PUTENV
|
||||
|
||||
/* Define to 1 if you have the <resolv.h> header file. */
|
||||
#undef HAVE_RESOLV_H
|
||||
|
||||
/* Define to 1 if the system has the type 'socklen_t'. */
|
||||
#undef HAVE_SOCKLEN_T
|
||||
|
||||
/* Solaris/SunOS */
|
||||
#undef HAVE_SOLARIS
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#undef HAVE_STDIO_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the 'strsignal' function. */
|
||||
#undef HAVE_STRSIGNAL
|
||||
|
||||
/* Define to 1 if the system has the type 'struct addrinfo'. */
|
||||
#undef HAVE_STRUCT_ADDRINFO
|
||||
|
||||
/* Define to 1 if the system has the type 'struct arphdr'. */
|
||||
#undef HAVE_STRUCT_ARPHDR
|
||||
|
||||
/* Define to 1 if the system has the type 'struct ether_arp'. */
|
||||
#undef HAVE_STRUCT_ETHER_ARP
|
||||
|
||||
/* Define to 1 if the system has the type 'struct ether_header'. */
|
||||
#undef HAVE_STRUCT_ETHER_HEADER
|
||||
|
||||
/* Define to 1 if the system has the type 'struct icmp'. */
|
||||
#undef HAVE_STRUCT_ICMP
|
||||
|
||||
/* Define to 1 if the system has the type 'struct icmp6_hdr'. */
|
||||
#undef HAVE_STRUCT_ICMP6_HDR
|
||||
|
||||
/* Define to 1 if the system has the type 'struct in6_addr'. */
|
||||
#undef HAVE_STRUCT_IN6_ADDR
|
||||
|
||||
/* Define to 1 if the system has the type 'struct in_addr'. */
|
||||
#undef HAVE_STRUCT_IN_ADDR
|
||||
|
||||
/* Define to 1 if the system has the type 'struct ip'. */
|
||||
#undef HAVE_STRUCT_IP
|
||||
|
||||
/* Define to 1 if the system has the type 'struct ip6_hdr'. */
|
||||
#undef HAVE_STRUCT_IP6_HDR
|
||||
|
||||
/* Define to 1 if the system has the type 'struct nd_neighbor_solicit'. */
|
||||
#undef HAVE_STRUCT_ND_NEIGHBOR_SOLICIT
|
||||
|
||||
/* Define to 1 if the system has the type 'struct nd_opt_hdr'. */
|
||||
#undef HAVE_STRUCT_ND_OPT_HDR
|
||||
|
||||
/* Define to 1 if the system has the type 'struct sockaddr_in6'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_IN6
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#undef HAVE_SYSLOG_H
|
||||
|
||||
/* Define to 1 if you have the 'system' function. */
|
||||
#undef HAVE_SYSTEM
|
||||
|
||||
/* Define to 1 if you have the <sys/file.h> header file. */
|
||||
#undef HAVE_SYS_FILE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/mman.h> header file. */
|
||||
#undef HAVE_SYS_MMAN_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
#undef HAVE_SYS_RESOURCE_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/uio.h> header file. */
|
||||
#undef HAVE_SYS_UIO_H
|
||||
|
||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||
#undef HAVE_SYS_WAIT_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the 'unsetenv' function. */
|
||||
#undef HAVE_UNSETENV
|
||||
|
||||
/* Define to 1 if you have the 'usleep' function. */
|
||||
#undef HAVE_USLEEP
|
||||
|
||||
/* Define to 1 if you have the 'vsyslog' function. */
|
||||
#undef HAVE_VSYSLOG
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
#undef HAVE_WCHAR_H
|
||||
|
||||
/* have zlib compression support */
|
||||
#undef HAVE_ZLIB
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#undef HAVE_ZLIB_H
|
||||
|
||||
/* Location of lzo1x.h */
|
||||
#undef LZO1X_H
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if all of the C89 standard headers exist (not just the ones
|
||||
required in a freestanding environment). This macro is provided for
|
||||
backward compatibility; new code need not use it. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Enable extensions on AIX, Interix, z/OS. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on macOS. */
|
||||
#ifndef _DARWIN_C_SOURCE
|
||||
# undef _DARWIN_C_SOURCE
|
||||
#endif
|
||||
/* Enable general extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# undef __EXTENSIONS__
|
||||
#endif
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
/* Enable X/Open compliant socket functions that do not require linking
|
||||
with -lxnet on HP-UX 11.11. */
|
||||
#ifndef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
# undef _HPUX_ALT_XOPEN_SOCKET_API
|
||||
#endif
|
||||
/* Identify the host operating system as Minix.
|
||||
This macro does not affect the system headers' behavior.
|
||||
A future release of Autoconf may stop defining this macro. */
|
||||
#ifndef _MINIX
|
||||
# undef _MINIX
|
||||
#endif
|
||||
/* Enable general extensions on NetBSD.
|
||||
Enable NetBSD compatibility extensions on Minix. */
|
||||
#ifndef _NETBSD_SOURCE
|
||||
# undef _NETBSD_SOURCE
|
||||
#endif
|
||||
/* Enable OpenBSD compatibility extensions on NetBSD.
|
||||
Oddly enough, this does nothing on OpenBSD. */
|
||||
#ifndef _OPENBSD_SOURCE
|
||||
# undef _OPENBSD_SOURCE
|
||||
#endif
|
||||
/* Define to 1 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_SOURCE
|
||||
# undef _POSIX_SOURCE
|
||||
#endif
|
||||
/* Define to 2 if needed for POSIX-compatible behavior. */
|
||||
#ifndef _POSIX_1_SOURCE
|
||||
# undef _POSIX_1_SOURCE
|
||||
#endif
|
||||
/* Enable POSIX-compatible threading on Solaris. */
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# undef _POSIX_PTHREAD_SEMANTICS
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
|
||||
#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_BFP_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_DFP_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by C23 Annex F. */
|
||||
#ifndef __STDC_WANT_IEC_60559_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_FUNCS_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */
|
||||
#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
# undef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
|
||||
#ifndef __STDC_WANT_LIB_EXT2__
|
||||
# undef __STDC_WANT_LIB_EXT2__
|
||||
#endif
|
||||
/* Enable extensions specified by ISO/IEC 24747:2009. */
|
||||
#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
# undef __STDC_WANT_MATH_SPEC_FUNCS__
|
||||
#endif
|
||||
/* Enable extensions on HP NonStop. */
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# undef _TANDEM_SOURCE
|
||||
#endif
|
||||
/* Enable X/Open extensions. Define to 500 only if necessary
|
||||
to make mbstate_t available. */
|
||||
#ifndef _XOPEN_SOURCE
|
||||
# undef _XOPEN_SOURCE
|
||||
#endif
|
||||
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Compile with support for Windows 2000 */
|
||||
#undef WITH_WINDOWS2000
|
||||
|
||||
/* Enable BSD extensions */
|
||||
#undef __USE_BSD
|
||||
|
||||
/* Defined if the __malloc__ attribute is not supported. */
|
||||
#undef __malloc__
|
||||
|
||||
/* Define as a signed integer type capable of holding a process identifier. */
|
||||
#undef pid_t
|
||||
2354
config.sub
vendored
Executable file
2354
config.sub
vendored
Executable file
File diff suppressed because it is too large
Load diff
245
configure.ac
Normal file
245
configure.ac
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.72])
|
||||
AC_INIT([tinc], [1.0.37])
|
||||
AC_CONFIG_SRCDIR([src/tincd.c])
|
||||
AM_INIT_AUTOMAKE([1.11 check-news std-options subdir-objects nostdinc silent-rules -Wall])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
# Enable GNU extensions.
|
||||
# Define this here, not in acconfig's @TOP@ section, since definitions
|
||||
# in the latter don't make it into the configure-time tests.
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_DEFINE([__USE_BSD], 1, [Enable BSD extensions])
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
AM_PROG_CC_C_O
|
||||
|
||||
dnl Check and set OS
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
case $host_os in
|
||||
*linux*)
|
||||
linux=true
|
||||
AC_DEFINE(HAVE_LINUX, 1, [Linux])
|
||||
;;
|
||||
*freebsd*)
|
||||
bsd=true
|
||||
AC_DEFINE(HAVE_FREEBSD, 1, [FreeBSD])
|
||||
;;
|
||||
*darwin*)
|
||||
bsd=true
|
||||
AC_DEFINE(HAVE_DARWIN, 1, [Darwin (MacOS/X)])
|
||||
;;
|
||||
*solaris*)
|
||||
solaris=true
|
||||
AC_DEFINE(HAVE_SOLARIS, 1, [Solaris/SunOS])
|
||||
;;
|
||||
*openbsd*)
|
||||
bsd=true
|
||||
AC_DEFINE(HAVE_OPENBSD, 1, [OpenBSD])
|
||||
;;
|
||||
*netbsd*)
|
||||
bsd=true
|
||||
AC_DEFINE(HAVE_NETBSD, 1, [NetBSD])
|
||||
;;
|
||||
*dragonfly*)
|
||||
bsd=true
|
||||
AC_DEFINE(HAVE_DRAGONFLY, 1, [DragonFly])
|
||||
;;
|
||||
*bsd*)
|
||||
bsd=true
|
||||
AC_MSG_WARN("Unknown BSD variant, tinc might not compile or work!")
|
||||
AC_DEFINE(HAVE_BSD, 1, [Unknown BSD variant])
|
||||
;;
|
||||
*cygwin*)
|
||||
cygwin=true
|
||||
AC_DEFINE(HAVE_CYGWIN, 1, [Cygwin])
|
||||
;;
|
||||
*mingw*)
|
||||
mingw=true
|
||||
AC_DEFINE(HAVE_MINGW, 1, [MinGW])
|
||||
LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR("Unknown operating system.")
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_ARG_ENABLE(uml,
|
||||
AS_HELP_STRING([--enable-uml], [enable support for User Mode Linux]),
|
||||
[ AS_IF([test "x$enable_uml" = "xyes"],
|
||||
[ AC_DEFINE(ENABLE_UML, 1, [Support for UML])
|
||||
uml=true
|
||||
],
|
||||
[uml=false])
|
||||
],
|
||||
[uml=false]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(vde,
|
||||
AS_HELP_STRING([--enable-vde], [enable support for Virtual Distributed Ethernet]),
|
||||
[ AS_IF([test "x$enable_vde" = "xyes"],
|
||||
[ AC_CHECK_HEADERS(libvdeplug_dyn.h, [], [AC_MSG_ERROR([VDE plug header files not found.]); break])
|
||||
AC_DEFINE(ENABLE_VDE, 1, [Support for VDE])
|
||||
vde=true
|
||||
],
|
||||
[vde=false])
|
||||
],
|
||||
[vde=false]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(tunemu,
|
||||
AS_HELP_STRING([--enable-tunemu], [enable support for the tunemu driver]),
|
||||
[ AS_IF([test "x$enable_tunemu" = "xyes"],
|
||||
[ AC_DEFINE(ENABLE_TUNEMU, 1, [Support for tunemu])
|
||||
tunemu=true
|
||||
],
|
||||
[tunemu=false])
|
||||
],
|
||||
[tunemu=false]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(windows2000,
|
||||
AS_HELP_STRING([--with-windows2000], [compile with support for Windows 2000. This disables support for tunneling over existing IPv6 networks.]),
|
||||
[ AS_IF([test "x$with_windows2000" = "xyes"],
|
||||
[AC_DEFINE(WITH_WINDOWS2000, 1, [Compile with support for Windows 2000])])
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(systemd,
|
||||
AS_HELP_STRING([--with-systemd@<:@=DIR@:>@], [install systemd service files @<:@to DIR if specified@:>@]),
|
||||
[ systemd=true; systemd_path="$with_systemd" ],
|
||||
[ systemd=false ]
|
||||
)
|
||||
|
||||
AS_IF([test "x$with_systemd" = "xyes"], [systemd_path="\${libdir}/systemd/system"],
|
||||
[AS_IF([test "x$with_systemd" = "xno"], [systemd=false])])
|
||||
|
||||
AC_SUBST(systemd_path, $systemd_path)
|
||||
|
||||
AM_CONDITIONAL(LINUX, test "$linux" = true)
|
||||
AM_CONDITIONAL(BSD, test "$bsd" = true)
|
||||
AM_CONDITIONAL(SOLARIS, test "$solaris" = true)
|
||||
AM_CONDITIONAL(MINGW, test "$mingw" = true)
|
||||
AM_CONDITIONAL(CYGWIN, test "$cygwin" = true)
|
||||
AM_CONDITIONAL(UML, test "$uml" = true)
|
||||
AM_CONDITIONAL(VDE, test "$vde" = true)
|
||||
AM_CONDITIONAL(TUNEMU, test "$tunemu" = true)
|
||||
AM_CONDITIONAL(WITH_SYSTEMD, test "$systemd" = true)
|
||||
|
||||
AC_CACHE_SAVE
|
||||
|
||||
if test -d /sw/include ; then
|
||||
CPPFLAGS="$CPPFLAGS -I/sw/include"
|
||||
fi
|
||||
if test -d /sw/lib ; then
|
||||
LIBS="$LIBS -L/sw/lib"
|
||||
fi
|
||||
|
||||
dnl Compiler hardening flags
|
||||
dnl No -fstack-protector-all because it doesn't work on all platforms or architectures.
|
||||
|
||||
AX_CFLAGS_WARN_ALL(CFLAGS)
|
||||
|
||||
AC_ARG_ENABLE([hardening], AS_HELP_STRING([--disable-hardening], [disable compiler and linker hardening flags]))
|
||||
AS_IF([test "x$enable_hardening" != "xno"],
|
||||
[AX_CHECK_COMPILE_FLAG([-DFORTIFY_SOURCE=2], [CPPFLAGS="$CPPFLAGS -DFORTIFY_SOURCE=2"])
|
||||
AX_CHECK_COMPILE_FLAG([-fwrapv], [CPPFLAGS="$CPPFLAGS -fwrapv"],
|
||||
AX_CHECK_COMPILE_FLAG([-fno-strict-overflow], [CPPFLAGS="$CPPFLAGS -fno-strict-overflow"]))
|
||||
case $host_os in
|
||||
*mingw*)
|
||||
AX_CHECK_LINK_FLAG([-Wl,--dynamicbase], [LDFLAGS="$LDFLAGS -Wl,--dynamicbase"])
|
||||
AX_CHECK_LINK_FLAG([-Wl,--nxcompat], [LDFLAGS="$LDFLAGS -Wl,--nxcompat"])
|
||||
;;
|
||||
*)
|
||||
AX_CHECK_COMPILE_FLAG([-fPIE], [CPPFLAGS="$CPPFLAGS -fPIE"])
|
||||
AX_CHECK_LINK_FLAG([-pie], [LDFLAGS="$LDFLAGS -pie"])
|
||||
;;
|
||||
esac
|
||||
AX_CHECK_LINK_FLAG([-Wl,-z,relro], [LDFLAGS="$LDFLAGS -Wl,-z,relro"])
|
||||
AX_CHECK_LINK_FLAG([-Wl,-z,now], [LDFLAGS="$LDFLAGS -Wl,-z,now"])
|
||||
]
|
||||
);
|
||||
|
||||
dnl Checks for libraries.
|
||||
|
||||
dnl Checks for header files.
|
||||
dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies.
|
||||
|
||||
AC_CHECK_HEADERS([syslog.h sys/file.h sys/ioctl.h sys/mman.h sys/param.h sys/resource.h sys/socket.h sys/time.h sys/uio.h sys/wait.h netdb.h arpa/inet.h arpa/nameser.h dirent.h getopt.h])
|
||||
AC_CHECK_HEADERS([net/if.h net/if_types.h linux/if_tun.h net/if_tun.h net/if_utun.h net/tun/if_tun.h net/if_tap.h net/tap/if_tap.h net/ethernet.h net/if_arp.h netinet/in_systm.h netinet/in.h netinet/in6.h netpacket/packet.h],
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
AC_CHECK_HEADERS([netinet/if_ether.h netinet/ip.h netinet/ip6.h resolv.h],
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
AC_CHECK_HEADERS([netinet/tcp.h netinet/ip_icmp.h netinet/icmp6.h],
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_TYPE_PID_T
|
||||
|
||||
tinc_ATTRIBUTE(__malloc__)
|
||||
|
||||
AC_CHECK_TYPES([socklen_t, struct ether_header, struct arphdr, struct ether_arp, struct in_addr, struct addrinfo, struct ip, struct icmp, struct in6_addr, struct sockaddr_in6, struct ip6_hdr, struct icmp6_hdr, struct nd_neighbor_solicit, struct nd_opt_hdr], , ,
|
||||
[#include "$srcdir/src/have.h"]
|
||||
)
|
||||
|
||||
dnl Checks for library functions.
|
||||
|
||||
AC_CHECK_FUNCS([asprintf daemon fchmod flock fork gettimeofday mlockall pselect putenv strsignal system unsetenv usleep vsyslog devname fdevname],
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
|
||||
AC_CHECK_FUNC(getopt_long, [getopt=true; AC_DEFINE(HAVE_GETOPT_LONG, 1, [getopt_long()])], [getopt=false])
|
||||
AM_CONDITIONAL(GETOPT, test "$getopt" = true)
|
||||
|
||||
dnl Support for SunOS
|
||||
|
||||
AC_CHECK_FUNC(socket, [], [
|
||||
AC_CHECK_LIB(socket, connect)
|
||||
])
|
||||
AC_CHECK_FUNC(gethostbyname, [], [
|
||||
AC_CHECK_LIB(nsl, gethostbyname)
|
||||
])
|
||||
|
||||
AC_CHECK_DECLS([freeaddrinfo, gai_strerror, getaddrinfo, getnameinfo],
|
||||
[], [], [#include "$srcdir/src/have.h"]
|
||||
)
|
||||
|
||||
AC_CHECK_DECLS([res_init], [AC_CHECK_LIB(resolv, res_init)], [], [
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h>
|
||||
])
|
||||
|
||||
AC_CACHE_SAVE
|
||||
|
||||
dnl These are defined in files in m4/
|
||||
|
||||
tinc_ZLIB
|
||||
tinc_LZO
|
||||
tinc_OPENSSL
|
||||
|
||||
dnl Check if support for jumbograms is requested
|
||||
AC_ARG_ENABLE(jumbograms,
|
||||
AS_HELP_STRING([--enable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
|
||||
[ AS_IF([test "x$enable_jumbograms" = "xyes"],
|
||||
[ AC_DEFINE(ENABLE_JUMBOGRAMS, 1, [Support for jumbograms (packets up to 9000 bytes)]) ])
|
||||
]
|
||||
)
|
||||
|
||||
dnl Ensure runstatedir is set if we are using a version of autoconf that does not support it
|
||||
if test "x$runstatedir" = "x"; then
|
||||
AC_SUBST([runstatedir], ['${localstatedir}/run'])
|
||||
fi
|
||||
|
||||
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile systemd/Makefile])
|
||||
|
||||
AC_OUTPUT
|
||||
792
depcomp
Executable file
792
depcomp
Executable file
|
|
@ -0,0 +1,792 @@
|
|||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2025-06-18.21; # UTC
|
||||
|
||||
# Copyright (C) 1999-2025 Free Software Foundation, Inc.
|
||||
|
||||
# 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, 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
GNU Automake home page: <https://www.gnu.org/software/automake/>.
|
||||
General help using GNU software: <https://www.gnu.org/gethelp/>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp (GNU Automake) $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Get the directory component of the given path, and save it in the
|
||||
# global variables '$dir'. Note that this directory component will
|
||||
# be either empty or ending with a '/' character. This is deliberate.
|
||||
set_dir_from ()
|
||||
{
|
||||
case $1 in
|
||||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
|
||||
*) dir=;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the suffix-stripped basename of the given path, and save it the
|
||||
# global variable '$base'.
|
||||
set_base_from ()
|
||||
{
|
||||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
|
||||
}
|
||||
|
||||
# If no dependency file was actually created by the compiler invocation,
|
||||
# we still have to create a dummy depfile, to avoid errors with the
|
||||
# Makefile "include basename.Plo" scheme.
|
||||
make_dummy_depfile ()
|
||||
{
|
||||
echo "#dummy" > "$depfile"
|
||||
}
|
||||
|
||||
# Factor out some common post-processing of the generated depfile.
|
||||
# Requires the auxiliary global variable '$tmpdepfile' to be set.
|
||||
aix_post_process_depfile ()
|
||||
{
|
||||
# If the compiler actually managed to produce a dependency file,
|
||||
# post-process it.
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form 'foo.o: dependency.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# $object: dependency.h
|
||||
# and one to simply output
|
||||
# dependency.h:
|
||||
# which is needed to avoid the deleted-header problem.
|
||||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
|
||||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
|
||||
} > "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
}
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
# Character ranges might be problematic outside the C locale.
|
||||
# These definitions help.
|
||||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
lower=abcdefghijklmnopqrstuvwxyz
|
||||
alpha=${upper}${lower}
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Avoid interference from the environment.
|
||||
gccflag= dashmflag=
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## Note that this doesn't just cater to obsolete pre-3.x GCC compilers.
|
||||
## but also to in-use compilers like IBM xlc/xlC and the HP C compiler.
|
||||
## (see the conditional assignment to $gccflag above).
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say). Also, it might not be
|
||||
## supported by the other compilers which use the 'gcc' depmode.
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The second -e expression handles DOS-style file names with drive
|
||||
# letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
|
||||
| tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
tcc)
|
||||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
|
||||
# FIXME: That version still under development at the moment of writing.
|
||||
# Make that this statement remains true also for stable, released
|
||||
# versions.
|
||||
# It will wrap lines (doesn't matter whether long or short) with a
|
||||
# trailing '\', as in:
|
||||
#
|
||||
# foo.o : \
|
||||
# foo.c \
|
||||
# foo.h \
|
||||
#
|
||||
# It will put a trailing '\' even on the last line, and will use leading
|
||||
# spaces rather than leading tabs (at least since its commit 0394caf7
|
||||
# "Emit spaces for -MD").
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
|
||||
# We have to change lines of the first kind to '$object: \'.
|
||||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
|
||||
# And for each line of the second kind, we have to emit a 'dep.h:'
|
||||
# dummy dependency, to avoid the deleted-header problem.
|
||||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
## The order of this option in the case statement is important, since the
|
||||
## shell code in configure will try each of these formats in the order
|
||||
## listed in this file. A plain '-MD' option would be understood by many
|
||||
## compilers, so we must ensure this comes after the gcc and icc options.
|
||||
pgcc)
|
||||
# Portland's C compiler understands '-MD'.
|
||||
# Will always output deps to 'file.d' where file is the root name of the
|
||||
# source file under compilation, even if file resides in a subdirectory.
|
||||
# The object file name does not affect the name of the '.d' file.
|
||||
# pgcc 10.2 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using '\' :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
set_dir_from "$object"
|
||||
# Use the source, not the object, to determine the base name, since
|
||||
# that's sadly what pgcc will do too.
|
||||
set_base_from "$source"
|
||||
tmpdepfile=$base.d
|
||||
|
||||
# For projects that build the same source file twice into different object
|
||||
# files, the pgcc approach of using the *source* file root name can cause
|
||||
# problems in parallel builds. Use a locking strategy to avoid stomping on
|
||||
# the same $tmpdepfile.
|
||||
lockdir=$base.d-lock
|
||||
trap "
|
||||
echo '$0: caught signal, cleaning up...' >&2
|
||||
rmdir '$lockdir'
|
||||
exit 1
|
||||
" 1 2 13 15
|
||||
numtries=100
|
||||
i=$numtries
|
||||
while test $i -gt 0; do
|
||||
# mkdir is a portable test-and-set.
|
||||
if mkdir "$lockdir" 2>/dev/null; then
|
||||
# This process acquired the lock.
|
||||
"$@" -MD
|
||||
stat=$?
|
||||
# Release the lock.
|
||||
rmdir "$lockdir"
|
||||
break
|
||||
else
|
||||
# If the lock is being held by a different process, wait
|
||||
# until the winning process is done or we timeout.
|
||||
while test -d "$lockdir" && test $i -gt 0; do
|
||||
sleep 1
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
fi
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
trap - 1 2 13 15
|
||||
if test $i -le 0; then
|
||||
echo "$0: failed to acquire lock after $numtries attempts" >&2
|
||||
echo "$0: check lockdir '$lockdir'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# Libtool generates 2 separate objects for the 2 libraries. These
|
||||
# two compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
|
||||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
# Same post-processing that is required for AIX mode.
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this sed invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process the last invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed '1,2d' "$tmpdepfile" \
|
||||
| tr ' ' "$nl" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E \
|
||||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
| sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp nil t)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%Y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
35
doc/Makefile.am
Normal file
35
doc/Makefile.am
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
## Process this file with automake to get Makefile.in
|
||||
|
||||
info_TEXINFOS = tinc.texi
|
||||
tinc_TEXINFOS = tincinclude.texi
|
||||
|
||||
man_MANS = tincd.8 tinc.conf.5
|
||||
|
||||
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config
|
||||
|
||||
CLEANFILES = *.html tincd.8 tinc.conf.5 tincinclude.texi
|
||||
|
||||
texi2html: tinc.texi
|
||||
$(AM_V_GEN)texi2html -split=chapter $<
|
||||
|
||||
tincd.8.html: tincd.8
|
||||
$(AM_V_GEN)w3mman2html $< > $@
|
||||
|
||||
tinc.conf.5.html: tinc.conf.5
|
||||
$(AM_V_GEN)w3mman2html $< > $@
|
||||
|
||||
substitute = sed \
|
||||
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
|
||||
-e s,'@VERSION\@',"$(VERSION)",g \
|
||||
-e s,'@sysconfdir\@',"$(sysconfdir)",g \
|
||||
-e s,'@runstatedir\@',"$(runstatedir)",g \
|
||||
-e s,'@localstatedir\@',"$(localstatedir)",g
|
||||
|
||||
tincd.8: $(srcdir)/tincd.8.in
|
||||
$(AM_V_GEN)$(substitute) $(srcdir)/tincd.8.in > $@
|
||||
|
||||
tinc.conf.5: $(srcdir)/tinc.conf.5.in
|
||||
$(AM_V_GEN)$(substitute) $(srcdir)/tinc.conf.5.in > $@
|
||||
|
||||
tincinclude.texi: $(srcdir)/tincinclude.texi.in
|
||||
$(AM_V_GEN)$(substitute) $(srcdir)/tincinclude.texi.in > $@
|
||||
862
doc/Makefile.in
Normal file
862
doc/Makefile.in
Normal file
|
|
@ -0,0 +1,862 @@
|
|||
# Makefile.in generated by automake 1.18.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2025 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
am__rm_f = rm -f $(am__rm_f_notfound)
|
||||
am__rm_rf = rm -rf $(am__rm_f_notfound)
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = doc
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/ax_append_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
|
||||
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_check_link_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_require_defined.m4 $(top_srcdir)/m4/lzo.m4 \
|
||||
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
AM_V_DVIPS = $(am__v_DVIPS_@AM_V@)
|
||||
am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@)
|
||||
am__v_DVIPS_0 = @echo " DVIPS " $@;
|
||||
am__v_DVIPS_1 =
|
||||
AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@)
|
||||
am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@)
|
||||
am__v_MAKEINFO_0 = @echo " MAKEINFO" $@;
|
||||
am__v_MAKEINFO_1 =
|
||||
AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@)
|
||||
am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@)
|
||||
am__v_INFOHTML_0 = @echo " INFOHTML" $@;
|
||||
am__v_INFOHTML_1 =
|
||||
AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@)
|
||||
am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@)
|
||||
am__v_TEXI2DVI_0 = @echo " TEXI2DVI" $@;
|
||||
am__v_TEXI2DVI_1 =
|
||||
AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@)
|
||||
am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@)
|
||||
am__v_TEXI2PDF_0 = @echo " TEXI2PDF" $@;
|
||||
am__v_TEXI2PDF_1 =
|
||||
AM_V_texinfo = $(am__v_texinfo_@AM_V@)
|
||||
am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@)
|
||||
am__v_texinfo_0 = -q
|
||||
am__v_texinfo_1 =
|
||||
AM_V_texidevnull = $(am__v_texidevnull_@AM_V@)
|
||||
am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@)
|
||||
am__v_texidevnull_0 = > /dev/null
|
||||
am__v_texidevnull_1 =
|
||||
INFO_DEPS = $(srcdir)/tinc.info
|
||||
am__TEXINFO_TEX_DIR = $(srcdir)
|
||||
DVIS = tinc.dvi
|
||||
PDFS = tinc.pdf
|
||||
PSS = tinc.ps
|
||||
HTMLS = tinc.html
|
||||
TEXINFOS = tinc.texi
|
||||
TEXI2DVI = texi2dvi
|
||||
TEXI2PDF = $(TEXI2DVI) --pdf --batch
|
||||
MAKEINFOHTML = $(MAKEINFO) --html
|
||||
AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
|
||||
DVIPS = dvips
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man5dir)" \
|
||||
"$(DESTDIR)$(man8dir)"
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
{ test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \
|
||||
}
|
||||
man5dir = $(mandir)/man5
|
||||
man8dir = $(mandir)/man8
|
||||
NROFF = nroff
|
||||
MANS = $(man_MANS)
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(tinc_TEXINFOS) texinfo.tex
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CSCOPE = @CSCOPE@
|
||||
CTAGS = @CTAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
ETAGS = @ETAGS@
|
||||
EXEEXT = @EXEEXT@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
OBJEXT = @OBJEXT@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__rm_f_notfound = @am__rm_f_notfound@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
am__xargs_n = @am__xargs_n@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
systemd_path = @systemd_path@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
info_TEXINFOS = tinc.texi
|
||||
tinc_TEXINFOS = tincinclude.texi
|
||||
man_MANS = tincd.8 tinc.conf.5
|
||||
EXTRA_DIST = tincinclude.texi.in tincd.8.in tinc.conf.5.in sample-config
|
||||
CLEANFILES = *.html tincd.8 tinc.conf.5 tincinclude.texi
|
||||
substitute = sed \
|
||||
-e s,'@PACKAGE\@',"$(PACKAGE)",g \
|
||||
-e s,'@VERSION\@',"$(VERSION)",g \
|
||||
-e s,'@sysconfdir\@',"$(sysconfdir)",g \
|
||||
-e s,'@runstatedir\@',"$(runstatedir)",g \
|
||||
-e s,'@localstatedir\@',"$(localstatedir)",g
|
||||
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .dvi .html .info .pdf .ps .texi
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu doc/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
.texi.info:
|
||||
$(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \
|
||||
am__cwd=`pwd` && $(am__cd) $(srcdir) && \
|
||||
rm -rf $$backupdir && mkdir $$backupdir && \
|
||||
if ($(MAKEINFO) --version) >/dev/null 2>&1; then \
|
||||
for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \
|
||||
if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \
|
||||
done; \
|
||||
else :; fi && \
|
||||
cd "$$am__cwd"; \
|
||||
if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
|
||||
-o $@ $<; \
|
||||
then \
|
||||
rc=0; \
|
||||
$(am__cd) $(srcdir); \
|
||||
else \
|
||||
rc=$$?; \
|
||||
$(am__cd) $(srcdir) && \
|
||||
$$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \
|
||||
fi; \
|
||||
rm -rf $$backupdir; exit $$rc
|
||||
|
||||
.texi.dvi:
|
||||
$(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
|
||||
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
|
||||
$(TEXI2DVI) $(AM_TEXI2FLAGS) -I $(srcdir) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \
|
||||
$<
|
||||
|
||||
.texi.pdf:
|
||||
$(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
|
||||
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
|
||||
$(TEXI2PDF) $(AM_TEXI2FLAGS) -I $(srcdir) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \
|
||||
$<
|
||||
|
||||
.texi.html:
|
||||
$(AM_V_MAKEINFO)rm -rf $(@:.html=.htp)
|
||||
$(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
|
||||
-o $(@:.html=.htp) $<; \
|
||||
then \
|
||||
rm -rf $@ && mv $(@:.html=.htp) $@; \
|
||||
else \
|
||||
rm -rf $(@:.html=.htp); exit 1; \
|
||||
fi
|
||||
$(srcdir)/tinc.info: tinc.texi $(tinc_TEXINFOS)
|
||||
tinc.dvi: tinc.texi $(tinc_TEXINFOS)
|
||||
tinc.pdf: tinc.texi $(tinc_TEXINFOS)
|
||||
tinc.html: tinc.texi $(tinc_TEXINFOS)
|
||||
.dvi.ps:
|
||||
$(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
|
||||
$(DVIPS) $(AM_V_texinfo) -o $@ $<
|
||||
|
||||
uninstall-dvi-am:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(DVIS)'; test -n "$(dvidir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(dvidir)/$$f"; \
|
||||
done
|
||||
|
||||
uninstall-html-am:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(HTMLS)'; test -n "$(htmldir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
rm -rf "$(DESTDIR)$(htmldir)/$$f"; \
|
||||
done
|
||||
|
||||
uninstall-info-am:
|
||||
@$(PRE_UNINSTALL)
|
||||
@if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \
|
||||
list='$(INFO_DEPS)'; \
|
||||
for file in $$list; do \
|
||||
relfile=`echo "$$file" | sed 's|^.*/||'`; \
|
||||
echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \
|
||||
if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \
|
||||
then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \
|
||||
done; \
|
||||
else :; fi
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(INFO_DEPS)'; \
|
||||
for file in $$list; do \
|
||||
relfile=`echo "$$file" | sed 's|^.*/||'`; \
|
||||
relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \
|
||||
(if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \
|
||||
echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \
|
||||
rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \
|
||||
else :; fi); \
|
||||
done
|
||||
|
||||
uninstall-pdf-am:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(pdfdir)/$$f"; \
|
||||
done
|
||||
|
||||
uninstall-ps-am:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(PSS)'; test -n "$(psdir)" || list=; \
|
||||
for p in $$list; do \
|
||||
$(am__strip_dir) \
|
||||
echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(psdir)/$$f"; \
|
||||
done
|
||||
|
||||
dist-info: $(INFO_DEPS)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(INFO_DEPS)'; \
|
||||
for base in $$list; do \
|
||||
case $$base in \
|
||||
$(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
esac; \
|
||||
if test -f $$base; then d=.; else d=$(srcdir); fi; \
|
||||
base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \
|
||||
for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \
|
||||
if test -f $$file; then \
|
||||
relfile=`expr "$$file" : "$$d/\(.*\)"`; \
|
||||
test -f "$(distdir)/$$relfile" || \
|
||||
cp -p $$file "$(distdir)/$$relfile"; \
|
||||
else :; fi; \
|
||||
done; \
|
||||
done
|
||||
|
||||
mostlyclean-aminfo:
|
||||
-$(am__rm_rf) tinc.t2d tinc.t2p
|
||||
|
||||
clean-aminfo:
|
||||
-$(am__rm_rf) tinc.dvi tinc.pdf tinc.ps tinc.html
|
||||
|
||||
maintainer-clean-aminfo:
|
||||
@list='$(INFO_DEPS)'; for i in $$list; do \
|
||||
i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \
|
||||
echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \
|
||||
rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \
|
||||
done
|
||||
install-man5: $(man_MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list1=''; \
|
||||
list2='$(man_MANS)'; \
|
||||
test -n "$(man5dir)" \
|
||||
&& test -n "`echo $$list1$$list2`" \
|
||||
|| exit 0; \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \
|
||||
{ for i in $$list1; do echo "$$i"; done; \
|
||||
if test -n "$$list2"; then \
|
||||
for i in $$list2; do echo "$$i"; done \
|
||||
| sed -n '/\.5[a-z]*$$/p'; \
|
||||
fi; \
|
||||
} | while read p; do \
|
||||
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; echo "$$p"; \
|
||||
done | \
|
||||
sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
|
||||
sed 'N;N;s,\n, ,g' | { \
|
||||
list=; while read file base inst; do \
|
||||
if test "$$base" = "$$inst"; then list="$$list $$file"; else \
|
||||
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
|
||||
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
|
||||
fi; \
|
||||
done; \
|
||||
for i in $$list; do echo "$$i"; done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
test -z "$$files" || { \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
|
||||
done; }
|
||||
|
||||
uninstall-man5:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list=''; test -n "$(man5dir)" || exit 0; \
|
||||
files=`{ for i in $$list; do echo "$$i"; done; \
|
||||
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
|
||||
sed -n '/\.5[a-z]*$$/p'; \
|
||||
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
|
||||
dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
|
||||
install-man8: $(man_MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list1=''; \
|
||||
list2='$(man_MANS)'; \
|
||||
test -n "$(man8dir)" \
|
||||
&& test -n "`echo $$list1$$list2`" \
|
||||
|| exit 0; \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
|
||||
{ for i in $$list1; do echo "$$i"; done; \
|
||||
if test -n "$$list2"; then \
|
||||
for i in $$list2; do echo "$$i"; done \
|
||||
| sed -n '/\.8[a-z]*$$/p'; \
|
||||
fi; \
|
||||
} | while read p; do \
|
||||
if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; echo "$$p"; \
|
||||
done | \
|
||||
sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
|
||||
sed 'N;N;s,\n, ,g' | { \
|
||||
list=; while read file base inst; do \
|
||||
if test "$$base" = "$$inst"; then list="$$list $$file"; else \
|
||||
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
|
||||
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \
|
||||
fi; \
|
||||
done; \
|
||||
for i in $$list; do echo "$$i"; done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
test -z "$$files" || { \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \
|
||||
done; }
|
||||
|
||||
uninstall-man8:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list=''; test -n "$(man8dir)" || exit 0; \
|
||||
files=`{ for i in $$list; do echo "$$i"; done; \
|
||||
l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
|
||||
sed -n '/\.8[a-z]*$$/p'; \
|
||||
} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
|
||||
-e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
|
||||
dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
|
||||
tags TAGS:
|
||||
|
||||
ctags CTAGS:
|
||||
|
||||
cscope cscopelist:
|
||||
|
||||
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
$(MAKE) $(AM_MAKEFLAGS) \
|
||||
top_distdir="$(top_distdir)" distdir="$(distdir)" \
|
||||
dist-info
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(INFO_DEPS) $(MANS)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
-$(am__rm_f) $(CLEANFILES)
|
||||
|
||||
distclean-generic:
|
||||
-$(am__rm_f) $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-aminfo clean-generic mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am: $(DVIS)
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am: $(HTMLS)
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am: $(INFO_DEPS)
|
||||
|
||||
install-data-am: install-info-am install-man
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am: $(DVIS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(DVIS)'; test -n "$(dvidir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \
|
||||
done
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am: $(HTMLS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
$(am__strip_dir) \
|
||||
d2=$$d$$p; \
|
||||
if test -d "$$d2"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
|
||||
echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
|
||||
else \
|
||||
list2="$$list2 $$d2"; \
|
||||
fi; \
|
||||
done; \
|
||||
test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \
|
||||
done; }
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am: $(INFO_DEPS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
|
||||
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \
|
||||
fi; \
|
||||
for file in $$list; do \
|
||||
case $$file in \
|
||||
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
esac; \
|
||||
if test -f $$file; then d=.; else d=$(srcdir); fi; \
|
||||
file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \
|
||||
for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \
|
||||
$$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \
|
||||
if test -f $$ifile; then \
|
||||
echo "$$ifile"; \
|
||||
else : ; fi; \
|
||||
done; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done
|
||||
@$(POST_INSTALL)
|
||||
@if $(am__can_run_installinfo); then \
|
||||
list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
|
||||
for file in $$list; do \
|
||||
relfile=`echo "$$file" | sed 's|^.*/||'`; \
|
||||
echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\
|
||||
install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\
|
||||
done; \
|
||||
else : ; fi
|
||||
install-man: install-man5 install-man8
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am: $(PDFS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am: $(PSS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(PSS)'; test -n "$(psdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-aminfo \
|
||||
maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-aminfo mostlyclean-generic
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am: $(PDFS)
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am: $(PSS)
|
||||
|
||||
uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \
|
||||
uninstall-man uninstall-pdf-am uninstall-ps-am
|
||||
|
||||
uninstall-man: uninstall-man5 uninstall-man8
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: all all-am check check-am clean clean-aminfo clean-generic \
|
||||
cscopelist-am ctags-am dist-info distclean distclean-generic \
|
||||
distdir dvi dvi-am html html-am info info-am install \
|
||||
install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-man5 install-man8 install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-aminfo maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-aminfo mostlyclean-generic pdf pdf-am ps ps-am \
|
||||
tags-am uninstall uninstall-am uninstall-dvi-am \
|
||||
uninstall-html-am uninstall-info-am uninstall-man \
|
||||
uninstall-man5 uninstall-man8 uninstall-pdf-am uninstall-ps-am
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
texi2html: tinc.texi
|
||||
$(AM_V_GEN)texi2html -split=chapter $<
|
||||
|
||||
tincd.8.html: tincd.8
|
||||
$(AM_V_GEN)w3mman2html $< > $@
|
||||
|
||||
tinc.conf.5.html: tinc.conf.5
|
||||
$(AM_V_GEN)w3mman2html $< > $@
|
||||
|
||||
tincd.8: $(srcdir)/tincd.8.in
|
||||
$(AM_V_GEN)$(substitute) $(srcdir)/tincd.8.in > $@
|
||||
|
||||
tinc.conf.5: $(srcdir)/tinc.conf.5.in
|
||||
$(AM_V_GEN)$(substitute) $(srcdir)/tinc.conf.5.in > $@
|
||||
|
||||
tincinclude.texi: $(srcdir)/tincinclude.texi.in
|
||||
$(AM_V_GEN)$(substitute) $(srcdir)/tincinclude.texi.in > $@
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
|
||||
# Tell GNU make to disable its built-in pattern rules.
|
||||
%:: %,v
|
||||
%:: RCS/%,v
|
||||
%:: RCS/%
|
||||
%:: s.%
|
||||
%:: SCCS/s.%
|
||||
15
doc/sample-config/hosts/alpha
Normal file
15
doc/sample-config/hosts/alpha
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Sample host configuration file
|
||||
|
||||
# The real IP address of this tinc host. Can be used by other tinc hosts.
|
||||
Address = 123.234.35.67
|
||||
|
||||
# Portnumber for incoming connections. Default is 655.
|
||||
Port = 655
|
||||
|
||||
# Subnet on the virtual private network that is local for this host.
|
||||
Subnet = 192.168.1.0/24
|
||||
|
||||
# The public key generated by `tincd -n example -K' is stored here
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
...
|
||||
-----END RSA PUBLIC KEY-----
|
||||
16
doc/sample-config/hosts/beta
Normal file
16
doc/sample-config/hosts/beta
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Sample host configuration file
|
||||
# This file was generated by host beta.
|
||||
|
||||
# The real IP address of this tinc host. Can be used by other tinc hosts.
|
||||
Address = 123.45.67.189
|
||||
|
||||
# Portnumber for incoming connections. Default is 655.
|
||||
Port = 6500
|
||||
|
||||
# Subnet on the virtual private network that is local for this host.
|
||||
Subnet = 192.168.2.0/24
|
||||
|
||||
# The public key generated by `tincd -n example -K' is stored here
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
...
|
||||
-----END RSA PUBLIC KEY-----
|
||||
1
doc/sample-config/rsa_key.priv
Normal file
1
doc/sample-config/rsa_key.priv
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Generate this file with `tincd -n example -K`
|
||||
4
doc/sample-config/tinc-down
Normal file
4
doc/sample-config/tinc-down
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
# This file closes down the tap device.
|
||||
|
||||
ifconfig $INTERFACE down
|
||||
11
doc/sample-config/tinc-up
Normal file
11
doc/sample-config/tinc-up
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
# This file sets up the tap device.
|
||||
# It gives you the freedom to do anything you want with it.
|
||||
# Use the correct name for the tap device:
|
||||
# The environment variable $INTERFACE is set to the right name
|
||||
# on most platforms, but if it doesn't work try to set it manually.
|
||||
|
||||
# Give it the right ip and netmask. Remember, the subnet of the
|
||||
# tap device must be larger than that of the individual Subnets
|
||||
# as defined in the host configuration file!
|
||||
ifconfig $INTERFACE 192.168.1.1 netmask 255.255.0.0
|
||||
22
doc/sample-config/tinc.conf
Normal file
22
doc/sample-config/tinc.conf
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Sample tinc configuration file
|
||||
|
||||
# This is a comment.
|
||||
# Spaces and tabs are eliminated.
|
||||
# The = sign isn't strictly necessary any longer, though you may want
|
||||
# to leave it in as it improves readability :)
|
||||
# Variable names are treated case insensitive.
|
||||
|
||||
# The name of this tinc host. Required.
|
||||
Name = alpha
|
||||
|
||||
# The internet host to connect with.
|
||||
# Comment these out to make yourself a listen-only connection
|
||||
# You must use the name of another tinc host.
|
||||
# May be used multiple times for redundance.
|
||||
ConnectTo = beta
|
||||
|
||||
# The tap device tinc will use.
|
||||
# /dev/tap0 for FreeBSD or OpenBSD
|
||||
# /dev/tun0 for Solaris
|
||||
# /dev/net/tun for Linux tun/tap
|
||||
Device = /dev/net/tun
|
||||
12354
doc/texinfo.tex
Normal file
12354
doc/texinfo.tex
Normal file
File diff suppressed because it is too large
Load diff
667
doc/tinc.conf.5.in
Normal file
667
doc/tinc.conf.5.in
Normal file
|
|
@ -0,0 +1,667 @@
|
|||
.Dd 2016-10-29
|
||||
.Dt TINC.CONF 5
|
||||
.\" Manual page created by:
|
||||
.\" Ivo Timmermans
|
||||
.\" Guus Sliepen <guus@tinc-vpn.org>
|
||||
.Sh NAME
|
||||
.Nm tinc.conf
|
||||
.Nd tinc daemon configuration
|
||||
.Sh DESCRIPTION
|
||||
The files in the
|
||||
.Pa @sysconfdir@/tinc/
|
||||
directory contain runtime and security information for the tinc daemon.
|
||||
.Sh NETWORKS
|
||||
It is perfectly ok for you to run more than one tinc daemon.
|
||||
However, in its default form,
|
||||
you will soon notice that you can't use two different configuration files without the
|
||||
.Fl c
|
||||
option.
|
||||
.Pp
|
||||
We have thought of another way of dealing with this: network names.
|
||||
This means that you call
|
||||
.Nm
|
||||
with the
|
||||
.Fl n
|
||||
option, which will assign a name to this daemon.
|
||||
.Pp
|
||||
The effect of this is that the daemon will set its configuration root to
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa / ,
|
||||
where
|
||||
.Ar NETNAME
|
||||
is your argument to the
|
||||
.Fl n
|
||||
option.
|
||||
You'll notice that messages appear in syslog as coming from
|
||||
.Nm tincd. Ns Ar NETNAME .
|
||||
.Pp
|
||||
However, it is not strictly necessary that you call tinc with the
|
||||
.Fl n
|
||||
option.
|
||||
In this case, the network name would just be empty,
|
||||
and it will be used as such.
|
||||
.Nm tinc
|
||||
now looks for files in
|
||||
.Pa @sysconfdir@/tinc/ ,
|
||||
instead of
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa / ;
|
||||
the configuration file should be
|
||||
.Pa @sysconfdir@/tinc/tinc.conf ,
|
||||
and the host configuration files are now expected to be in
|
||||
.Pa @sysconfdir@/tinc/hosts/ .
|
||||
.Pp
|
||||
But it is highly recommended that you use this feature of
|
||||
.Nm tinc ,
|
||||
because it will be so much clearer whom your daemon talks to.
|
||||
Hence, we will assume that you use it.
|
||||
.Sh NAMES
|
||||
Each tinc daemon must have a name that is unique in the network which it will be part of.
|
||||
The name will be used by other tinc daemons for identification.
|
||||
The name has to be declared in the
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf
|
||||
file.
|
||||
.Pp
|
||||
To make things easy,
|
||||
choose something that will give unique and easy to remember names to your tinc daemon(s).
|
||||
You could try things like hostnames, owner surnames or location names.
|
||||
.Sh PUBLIC/PRIVATE KEYS
|
||||
You should use
|
||||
.Ic tincd -K
|
||||
to generate public/private keypairs.
|
||||
It will generate two keys.
|
||||
The private key should be stored in a separate file
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv
|
||||
\-\- where
|
||||
.Ar NETNAME
|
||||
stands for the network (see
|
||||
.Sx NETWORKS )
|
||||
above.
|
||||
The public key should be stored in the host configuration file
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Va NAME
|
||||
\-\- where
|
||||
.Va NAME
|
||||
stands for the name of the local tinc daemon (see
|
||||
.Sx NAMES ) .
|
||||
.Sh SERVER CONFIGURATION
|
||||
The server configuration of the daemon is done in the file
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf .
|
||||
This file consists of comments (lines started with a
|
||||
.Li # )
|
||||
or assignments in the form of:
|
||||
.Pp
|
||||
.Va Variable Li = Ar Value .
|
||||
.Pp
|
||||
The variable names are case insensitive, and any spaces, tabs,
|
||||
newlines and carriage returns are ignored.
|
||||
Note: it is not required that you put in the
|
||||
.Li =
|
||||
sign, but doing so improves readability.
|
||||
If you leave it out, remember to replace it with at least one space character.
|
||||
.Pp
|
||||
The server configuration is complemented with host specific configuration (see the next section).
|
||||
Although all configuration options for the local host listed in this document can also be put in
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf ,
|
||||
it is recommended to put host specific configuration options in the host configuration file,
|
||||
as this makes it easy to exchange with other nodes.
|
||||
.Pp
|
||||
Here are all valid variables, listed in alphabetical order.
|
||||
The default value is given between parentheses.
|
||||
.Bl -tag -width indent
|
||||
.It Va AddressFamily Li = ipv4 | ipv6 | any Pq any
|
||||
This option affects the address family of listening and outgoing sockets.
|
||||
If
|
||||
.Qq any
|
||||
is selected, then depending on the operating system both IPv4 and IPv6 or just
|
||||
IPv6 listening sockets will be created.
|
||||
.It Va BindToAddress Li = Ar address Oo Ar port Oc Bq experimental
|
||||
If your computer has more than one IPv4 or IPv6 address,
|
||||
.Nm tinc
|
||||
will by default listen on all of them for incoming connections.
|
||||
Multiple
|
||||
.Va BindToAddress
|
||||
variables may be specified,
|
||||
in which case listening sockets for each specified address are made.
|
||||
.Pp
|
||||
If no
|
||||
.Ar port
|
||||
is specified, the socket will be bound to the port specified by the
|
||||
.Va Port
|
||||
option, or to port 655 if neither is given.
|
||||
To only bind to a specific port but not to a specific address, use
|
||||
.Li *
|
||||
for the
|
||||
.Ar address .
|
||||
.Pp
|
||||
This option may not work on all platforms.
|
||||
.It Va BindToInterface Li = Ar interface Bq experimental
|
||||
If your computer has more than one network interface,
|
||||
.Nm tinc
|
||||
will by default listen on all of them for incoming connections.
|
||||
It is possible to bind only to a single interface with this variable.
|
||||
.Pp
|
||||
This option may not work on all platforms.
|
||||
Also, on some platforms it will not actually bind to an interface,
|
||||
but rather to the address that the interface has at the moment a socket is created.
|
||||
.It Va Broadcast Li = no | mst | direct Po mst Pc Bq experimental
|
||||
This option selects the way broadcast packets are sent to other daemons.
|
||||
NOTE: all nodes in a VPN must use the same
|
||||
.Va Broadcast
|
||||
mode, otherwise routing loops can form.
|
||||
.Bl -tag -width indent
|
||||
.It no
|
||||
Broadcast packets are never sent to other nodes.
|
||||
.It mst
|
||||
Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
|
||||
This ensures broadcast packets reach all nodes.
|
||||
.It direct
|
||||
Broadcast packets are sent directly to all nodes that can be reached directly.
|
||||
Broadcast packets received from other nodes are never forwarded.
|
||||
If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
|
||||
.El
|
||||
.It Va ConnectTo Li = Ar name
|
||||
Specifies which other tinc daemon to connect to on startup.
|
||||
Multiple
|
||||
.Va ConnectTo
|
||||
variables may be specified,
|
||||
in which case outgoing connections to each specified tinc daemon are made.
|
||||
The names should be known to this tinc daemon
|
||||
(i.e., there should be a host configuration file for the name on the
|
||||
.Va ConnectTo
|
||||
line).
|
||||
.Pp
|
||||
If you don't specify a host with
|
||||
.Va ConnectTo ,
|
||||
.Nm tinc
|
||||
won't try to connect to other daemons at all,
|
||||
and will instead just listen for incoming connections.
|
||||
.It Va DecrementTTL Li = yes | no Po no Pc Bq experimental
|
||||
When enabled,
|
||||
.Nm tinc
|
||||
will decrement the Time To Live field in IPv4 packets, or the Hop Limit field in IPv6 packets,
|
||||
before forwarding a received packet to the virtual network device or to another node,
|
||||
and will drop packets that have a TTL value of zero,
|
||||
in which case it will send an ICMP Time Exceeded packet back.
|
||||
.Pp
|
||||
Do not use this option if you use switch mode and want to use IPv6.
|
||||
.It Va Device Li = Ar device Po Pa /dev/tap0 , Pa /dev/net/tun No or other depending on platform Pc
|
||||
The virtual network device to use.
|
||||
.Nm tinc
|
||||
will automatically detect what kind of device it is.
|
||||
Note that you can only use one device per daemon.
|
||||
Under Windows, use
|
||||
.Va Interface
|
||||
instead of
|
||||
.Va Device .
|
||||
The info pages of the tinc package contain more information
|
||||
about configuring the virtual network device.
|
||||
.It Va DeviceType Li = Ar type Pq platform dependent
|
||||
The type of the virtual network device.
|
||||
Tinc will normally automatically select the right type of tun/tap interface, and this option should not be used.
|
||||
However, this option can be used to select one of the special interface types, if support for them is compiled in.
|
||||
.Bl -tag -width indent
|
||||
.It dummy
|
||||
Use a dummy interface.
|
||||
No packets are ever read or written to a virtual network device.
|
||||
Useful for testing, or when setting up a node that only forwards packets for other nodes.
|
||||
.It raw_socket
|
||||
Open a raw socket, and bind it to a pre-existing
|
||||
.Va Interface
|
||||
(eth0 by default).
|
||||
All packets are read from this interface.
|
||||
Packets received for the local node are written to the raw socket.
|
||||
However, at least on Linux, the operating system does not process IP packets destined for the local host.
|
||||
.It multicast
|
||||
Open a multicast UDP socket and bind it to the address and port (separated by spaces) and optionally a TTL value specified using
|
||||
.Va Device .
|
||||
Packets are read from and written to this multicast socket.
|
||||
This can be used to connect to UML, QEMU or KVM instances listening on the same multicast address.
|
||||
Do NOT connect multiple
|
||||
.Nm tinc
|
||||
daemons to the same multicast address, this will very likely cause routing loops.
|
||||
Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
|
||||
.It uml Pq not compiled in by default
|
||||
Create a UNIX socket with the filename specified by
|
||||
.Va Device ,
|
||||
or
|
||||
.Pa @runstatedir@/ Ns Ar NETNAME Ns Pa .umlsocket
|
||||
if not specified.
|
||||
.Nm tinc
|
||||
will wait for a User Mode Linux instance to connect to this socket.
|
||||
.It vde Pq not compiled in by default
|
||||
Uses the libvdeplug library to connect to a Virtual Distributed Ethernet switch,
|
||||
using the UNIX socket specified by
|
||||
.Va Device ,
|
||||
or
|
||||
.Pa @runstatedir@/vde.ctl
|
||||
if not specified.
|
||||
.El
|
||||
Also, in case tinc does not seem to correctly interpret packets received from the virtual network device,
|
||||
it can be used to change the way packets are interpreted:
|
||||
.Bl -tag -width indent
|
||||
.It tun Pq BSD and Linux
|
||||
Set type to tun.
|
||||
Depending on the platform, this can either be with or without an address family header (see below).
|
||||
.It tunnohead Pq BSD
|
||||
Set type to tun without an address family header.
|
||||
Tinc will expect packets read from the virtual network device to start with an IP header.
|
||||
On some platforms IPv6 packets cannot be read from or written to the device in this mode.
|
||||
.It tunifhead Pq BSD
|
||||
Set type to tun with an address family header.
|
||||
Tinc will expect packets read from the virtual network device
|
||||
to start with a four byte header containing the address family,
|
||||
followed by an IP header.
|
||||
This mode should support both IPv4 and IPv6 packets.
|
||||
.It utun Pq OS X
|
||||
Set type to utun.
|
||||
This is only supported on OS X version 10.6.8 and higher, but doesn't require the tuntaposx module.
|
||||
This mode should support both IPv4 and IPv6 packets.
|
||||
.It tap Pq BSD and Linux
|
||||
Set type to tap.
|
||||
Tinc will expect packets read from the virtual network device
|
||||
to start with an Ethernet header.
|
||||
.El
|
||||
.It Va DirectOnly Li = yes | no Po no Pc Bq experimental
|
||||
When this option is enabled, packets that cannot be sent directly to the destination node,
|
||||
but which would have to be forwarded by an intermediate node, are dropped instead.
|
||||
When combined with the IndirectData option,
|
||||
packets for nodes for which we do not have a meta connection with are also dropped.
|
||||
.It Va Forwarding Li = off | internal | kernel Po internal Pc Bq experimental
|
||||
This option selects the way indirect packets are forwarded.
|
||||
.Bl -tag -width indent
|
||||
.It off
|
||||
Incoming packets that are not meant for the local node,
|
||||
but which should be forwarded to another node, are dropped.
|
||||
.It internal
|
||||
Incoming packets that are meant for another node are forwarded by tinc internally.
|
||||
.Pp
|
||||
This is the default mode, and unless you really know you need another forwarding mode, don't change it.
|
||||
.It kernel
|
||||
Incoming packets are always sent to the TUN/TAP device, even if the packets are not for the local node.
|
||||
This is less efficient, but allows the kernel to apply its routing and firewall rules on them,
|
||||
and can also help debugging.
|
||||
.El
|
||||
.It Va GraphDumpFile Li = Ar filename Bq experimental
|
||||
If this option is present,
|
||||
.Nm tinc
|
||||
will dump the current network graph to the file
|
||||
.Ar filename
|
||||
every minute, unless there were no changes to the graph.
|
||||
The file is in a format that can be read by graphviz tools.
|
||||
If
|
||||
.Ar filename
|
||||
starts with a pipe symbol |,
|
||||
then the rest of the filename is interpreted as a shell command
|
||||
that is executed, the graph is then sent to stdin.
|
||||
.It Va Hostnames Li = yes | no Pq no
|
||||
This option selects whether IP addresses (both real and on the VPN) should
|
||||
be resolved. Since DNS lookups are blocking, it might affect tinc's
|
||||
efficiency, even stopping the daemon for a few seconds every time it does
|
||||
a lookup if your DNS server is not responding.
|
||||
.Pp
|
||||
This does not affect resolving hostnames to IP addresses from the
|
||||
host configuration files, but whether hostnames should be resolved while logging.
|
||||
.It Va IffOneQueue Li = yes | no Po no Pc Bq experimental
|
||||
(Linux only) Set IFF_ONE_QUEUE flag on TUN/TAP devices.
|
||||
.It Va Interface Li = Ar interface
|
||||
Defines the name of the interface corresponding to the virtual network device.
|
||||
Depending on the operating system and the type of device this may or may not actually set the name of the interface.
|
||||
Under Windows, this variable is used to select which network interface will be used.
|
||||
If you specified a
|
||||
.Va Device ,
|
||||
this variable is almost always already correctly set.
|
||||
.It Va KeyExpire Li = Ar seconds Pq 3600
|
||||
This option controls the period the encryption keys used to encrypt the data are valid.
|
||||
It is common practice to change keys at regular intervals to make it even harder for crackers,
|
||||
even though it is thought to be nearly impossible to crack a single key.
|
||||
.It Va LocalDiscovery Li = yes | no Po no Pc Bq experimental
|
||||
When enabled,
|
||||
.Nm tinc
|
||||
will try to detect peers that are on the same local network.
|
||||
This will allow direct communication using LAN addresses, even if both peers are behind a NAT
|
||||
and they only ConnectTo a third node outside the NAT,
|
||||
which normally would prevent the peers from learning each other's LAN address.
|
||||
.Pp
|
||||
Currently, local discovery is implemented by sending broadcast packets to the LAN during path MTU discovery.
|
||||
This feature may not work in all possible situations.
|
||||
.It Va MACExpire Li = Ar seconds Pq 600
|
||||
This option controls the amount of time MAC addresses are kept before they are removed.
|
||||
This only has effect when
|
||||
.Va Mode
|
||||
is set to
|
||||
.Qq switch .
|
||||
.It Va MaxTimeout Li = Ar seconds Pq 900
|
||||
This is the maximum delay before trying to reconnect to other tinc daemons.
|
||||
.It Va Mode Li = router | switch | hub Pq router
|
||||
This option selects the way packets are routed to other daemons.
|
||||
.Bl -tag -width indent
|
||||
.It router
|
||||
In this mode
|
||||
.Va Subnet
|
||||
variables in the host configuration files will be used to form a routing table.
|
||||
Only unicast packets of routable protocols (IPv4 and IPv6) are supported in this mode.
|
||||
.Pp
|
||||
This is the default mode, and unless you really know you need another mode, don't change it.
|
||||
.It switch
|
||||
In this mode the MAC addresses of the packets on the VPN will be used to
|
||||
dynamically create a routing table just like an Ethernet switch does.
|
||||
Unicast, multicast and broadcast packets of every protocol that runs over Ethernet are supported in this mode
|
||||
at the cost of frequent broadcast ARP requests and routing table updates.
|
||||
.Pp
|
||||
This mode is primarily useful if you want to bridge Ethernet segments.
|
||||
.It hub
|
||||
This mode is almost the same as the switch mode, but instead
|
||||
every packet will be broadcast to the other daemons
|
||||
while no routing table is managed.
|
||||
.El
|
||||
.It Va Name Li = Ar name Bq required
|
||||
This is the name which identifies this tinc daemon.
|
||||
It must be unique for the virtual private network this daemon will connect to.
|
||||
The Name may only consist of alphanumeric and underscore characters.
|
||||
If
|
||||
.Va Name
|
||||
starts with a
|
||||
.Li $ ,
|
||||
then the contents of the environment variable that follows will be used.
|
||||
In that case, invalid characters will be converted to underscores.
|
||||
If
|
||||
.Va Name
|
||||
is
|
||||
.Li $HOST ,
|
||||
but no such environment variable exist, the hostname will be read using the gethostname() system call.
|
||||
.It Va PingInterval Li = Ar seconds Pq 60
|
||||
The number of seconds of inactivity that
|
||||
.Nm tinc
|
||||
will wait before sending a probe to the other end.
|
||||
.It Va PingTimeout Li = Ar seconds Pq 5
|
||||
The number of seconds to wait for a response to pings or to allow meta
|
||||
connections to block. If the other end doesn't respond within this time,
|
||||
the connection is terminated,
|
||||
and the others will be notified of this.
|
||||
.It Va PriorityInheritance Li = yes | no Po no Pc Bq experimental
|
||||
When this option is enabled the value of the TOS field of tunneled IPv4 packets
|
||||
will be inherited by the UDP packets that are sent out.
|
||||
.It Va PrivateKeyFile Li = Ar filename Po Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv Pc
|
||||
The file in which the private RSA key of this tinc daemon resides.
|
||||
.It Va ProcessPriority Li = low | normal | high
|
||||
When this option is used the priority of the tincd process will be adjusted.
|
||||
Increasing the priority may help to reduce latency and packet loss on the VPN.
|
||||
.It Va Proxy Li = socks4 | socks5 | http | exec Ar ... Bq experimental
|
||||
Use a proxy when making outgoing connections.
|
||||
The following proxy types are currently supported:
|
||||
.Bl -tag -width indent
|
||||
.It socks4 Ar address Ar port Op Ar username
|
||||
Connects to the proxy using the SOCKS version 4 protocol.
|
||||
Optionally, a
|
||||
.Ar username
|
||||
can be supplied which will be passed on to the proxy server.
|
||||
Only IPv4 connections can be proxied using SOCKS 4.
|
||||
.It socks5 Ar address Ar port Op Ar username Ar password
|
||||
Connect to the proxy using the SOCKS version 5 protocol.
|
||||
If a
|
||||
.Ar username
|
||||
and
|
||||
.Ar password
|
||||
are given, basic username/password authentication will be used,
|
||||
otherwise no authentication will be used.
|
||||
.It http Ar address Ar port
|
||||
Connects to the proxy and sends a HTTP CONNECT request.
|
||||
.It exec Ar command
|
||||
Executes the given
|
||||
.Ar command
|
||||
which should set up the outgoing connection.
|
||||
The environment variables
|
||||
.Ev NAME ,
|
||||
.Ev NODE ,
|
||||
.Ev REMOTEADDRES
|
||||
and
|
||||
.Ev REMOTEPORT
|
||||
are available.
|
||||
.El
|
||||
.It Va ReplayWindow Li = Ar bytes Pq 16
|
||||
This is the size of the replay tracking window for each remote node, in bytes.
|
||||
The window is a bitfield which tracks 1 packet per bit, so for example
|
||||
the default setting of 16 will track up to 128 packets in the window. In high
|
||||
bandwidth scenarios, setting this to a higher value can reduce packet loss from
|
||||
the interaction of replay tracking with underlying real packet loss and/or
|
||||
reordering. Setting this to zero will disable replay tracking completely and
|
||||
pass all traffic, but leaves tinc vulnerable to replay-based attacks on your
|
||||
traffic.
|
||||
.It Va StrictSubnets Li = yes | no Po no Pc Bq experimental
|
||||
When this option is enabled tinc will only use Subnet statements which are
|
||||
present in the host config files in the local
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/
|
||||
directory. Subnets learned via connections to other nodes and which are not
|
||||
present in the local host config files are ignored.
|
||||
.It Va TunnelServer Li = yes | no Po no Pc Bq experimental
|
||||
When this option is enabled tinc will no longer forward information between other tinc daemons,
|
||||
and will only allow connections with nodes for which host config files are present in the local
|
||||
.Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/
|
||||
directory.
|
||||
Setting this options also implicitly sets StrictSubnets.
|
||||
.It Va UDPRcvBuf Li = Ar bytes Pq OS default
|
||||
Sets the socket receive buffer size for the UDP socket, in bytes.
|
||||
If unset, the default buffer size will be used by the operating system.
|
||||
.It Va UDPSndBuf Li = Ar bytes Pq OS default
|
||||
Sets the socket send buffer size for the UDP socket, in bytes.
|
||||
If unset, the default buffer size will be used by the operating system.
|
||||
.El
|
||||
.Sh HOST CONFIGURATION FILES
|
||||
The host configuration files contain all information needed
|
||||
to establish a connection to those hosts.
|
||||
A host configuration file is also required for the local tinc daemon,
|
||||
it will use it to read in it's listen port, public key and subnets.
|
||||
.Pp
|
||||
The idea is that these files are portable.
|
||||
You can safely mail your own host configuration file to someone else.
|
||||
That other person can then copy it to his own hosts directory,
|
||||
and now his tinc daemon will be able to connect to your tinc daemon.
|
||||
Since host configuration files only contain public keys,
|
||||
no secrets are revealed by sending out this information.
|
||||
.Bl -tag -width indent
|
||||
.It Va Address Li = Ar address Oo Ar port Oc Bq recommended
|
||||
The IP address or hostname of this tinc daemon on the real network.
|
||||
This will only be used when trying to make an outgoing connection to this tinc daemon.
|
||||
Optionally, a port can be specified to use for this address.
|
||||
Multiple
|
||||
.Va Address
|
||||
variables can be specified, in which case each address will be tried until a working
|
||||
connection has been established.
|
||||
.It Va Cipher Li = Ar cipher Pq aes-256-cbc
|
||||
The symmetric cipher algorithm used to encrypt UDP packets.
|
||||
Any cipher supported by LibreSSL or OpenSSL is recognised.
|
||||
Furthermore, specifying
|
||||
.Qq none
|
||||
will turn off packet encryption.
|
||||
It is best to use only those ciphers which support CBC mode.
|
||||
.It Va ClampMSS Li = yes | no Pq yes
|
||||
This option specifies whether tinc should clamp the maximum segment size (MSS)
|
||||
of TCP packets to the path MTU. This helps in situations where ICMP
|
||||
Fragmentation Needed or Packet too Big messages are dropped by firewalls.
|
||||
.It Va Compression Li = Ar level Pq 0
|
||||
This option sets the level of compression used for UDP packets.
|
||||
Possible values are 0 (off), 1 (fast zlib) and any integer up to 9 (best zlib),
|
||||
10 (fast lzo) and 11 (best lzo).
|
||||
.It Va Digest Li = Ar digest Pq sha256
|
||||
The digest algorithm used to authenticate UDP packets.
|
||||
Any digest supported by LibreSSL or OpenSSL is recognised.
|
||||
Furthermore, specifying
|
||||
.Qq none
|
||||
will turn off packet authentication.
|
||||
.It Va IndirectData Li = yes | no Pq no
|
||||
When set to yes, only nodes which already have a meta connection to you
|
||||
will try to establish direct communication with you.
|
||||
It is best to leave this option out or set it to no.
|
||||
.It Va MACLength Li = Ar length Pq 4
|
||||
The length of the message authentication code used to authenticate UDP packets.
|
||||
Can be anything from
|
||||
.Qq 0
|
||||
up to the length of the digest produced by the digest algorithm.
|
||||
.It Va PMTU Li = Ar mtu Po 1514 Pc
|
||||
This option controls the initial path MTU to this node.
|
||||
.It Va PMTUDiscovery Li = yes | no Po yes Pc
|
||||
When this option is enabled, tinc will try to discover the path MTU to this node.
|
||||
After the path MTU has been discovered, it will be enforced on the VPN.
|
||||
.It Va Port Li = Ar port Pq 655
|
||||
The port number on which this tinc daemon is listening for incoming connections,
|
||||
which is used if no port number is specified in an
|
||||
.Va Address
|
||||
statement.
|
||||
.It Va PublicKeyFile Li = Ar filename Bq obsolete
|
||||
The file in which the public RSA key of this tinc daemon resides.
|
||||
.Pp
|
||||
From version 1.0pre4 on
|
||||
.Nm tinc
|
||||
will store the public key directly into the host configuration file in PEM format,
|
||||
the above two options then are not necessary.
|
||||
Either the PEM format is used, or exactly one of the above two options must be specified
|
||||
in each host configuration file,
|
||||
if you want to be able to establish a connection with that host.
|
||||
.It Va Subnet Li = Ar address Ns Op Li / Ns Ar prefixlength Ns Op Li # Ns Ar weight
|
||||
The subnet which this tinc daemon will serve.
|
||||
.Nm tinc
|
||||
tries to look up which other daemon it should send a packet to by searching the appropriate subnet.
|
||||
If the packet matches a subnet,
|
||||
it will be sent to the daemon who has this subnet in his host configuration file.
|
||||
Multiple
|
||||
.Va Subnet
|
||||
variables can be specified.
|
||||
.Pp
|
||||
Subnets can either be single MAC, IPv4 or IPv6 addresses,
|
||||
in which case a subnet consisting of only that single address is assumed,
|
||||
or they can be a IPv4 or IPv6 network address with a prefixlength.
|
||||
For example, IPv4 subnets must be in a form like 192.168.1.0/24,
|
||||
where 192.168.1.0 is the network address and 24 is the number of bits set in the netmask.
|
||||
Note that subnets like 192.168.1.1/24 are invalid!
|
||||
Read a networking HOWTO/FAQ/guide if you don't understand this.
|
||||
IPv6 subnets are notated like fec0:0:0:1::/64.
|
||||
MAC addresses are notated like 0:1a:2b:3c:4d:5e.
|
||||
.Pp
|
||||
A Subnet can be given a weight to indicate its priority over identical Subnets
|
||||
owned by different nodes. The default weight is 10. Lower values indicate
|
||||
higher priority. Packets will be sent to the node with the highest priority,
|
||||
unless that node is not reachable, in which case the node with the next highest
|
||||
priority will be tried, and so on.
|
||||
.It Va TCPOnly Li = yes | no Pq no Bq obsolete
|
||||
If this variable is set to yes,
|
||||
then the packets are tunnelled over the TCP connection instead of a UDP connection.
|
||||
This is especially useful for those who want to run a tinc daemon
|
||||
from behind a masquerading firewall,
|
||||
or if UDP packet routing is disabled somehow.
|
||||
Setting this options also implicitly sets IndirectData.
|
||||
.Pp
|
||||
Since version 1.0.10, tinc will automatically detect whether communication via
|
||||
UDP is possible or not.
|
||||
.El
|
||||
.Sh SCRIPTS
|
||||
Apart from reading the server and host configuration files,
|
||||
tinc can also run scripts at certain moments.
|
||||
Below is a list of filenames of scripts and a description of when they are run.
|
||||
A script is only run if it exists and if it is executable.
|
||||
.Pp
|
||||
Scripts are run synchronously;
|
||||
this means that tinc will temporarily stop processing packets until the called script finishes executing.
|
||||
This guarantees that scripts will execute in the exact same order as the events that trigger them.
|
||||
If you need to run commands asynchronously, you have to ensure yourself that they are being run in the background.
|
||||
.Pp
|
||||
Under Windows (not Cygwin), the scripts must have the extension
|
||||
.Pa .bat .
|
||||
.Bl -tag -width indent
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up
|
||||
This is the most important script.
|
||||
If it is present it will be executed right after the tinc daemon has been started and has connected to the virtual network device.
|
||||
It should be used to set up the corresponding network interface,
|
||||
but can also be used to start other things.
|
||||
.Pp
|
||||
Under Windows you can use the Network Connections control panel instead of creating this script.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-down
|
||||
This script is started right before the tinc daemon quits.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Ar HOST Ns Pa -up
|
||||
This script is started when the tinc daemon with name
|
||||
.Ar HOST
|
||||
becomes reachable.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/ Ns Ar HOST Ns Pa -down
|
||||
This script is started when the tinc daemon with name
|
||||
.Ar HOST
|
||||
becomes unreachable.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /host-up
|
||||
This script is started when any host becomes reachable.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /host-down
|
||||
This script is started when any host becomes unreachable.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /subnet-up
|
||||
This script is started when a Subnet becomes reachable.
|
||||
The Subnet and the node it belongs to are passed in environment variables.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /subnet-down
|
||||
This script is started when a Subnet becomes unreachable.
|
||||
.El
|
||||
.Pp
|
||||
The scripts are started without command line arguments, but can make use of certain environment variables.
|
||||
Under UNIX like operating systems the names of environment variables must be preceded by a
|
||||
.Li $
|
||||
in scripts.
|
||||
Under Windows, in
|
||||
.Pa .bat
|
||||
files, they have to be put between
|
||||
.Li %
|
||||
signs.
|
||||
.Bl -tag -width indent
|
||||
.It Ev NETNAME
|
||||
If a netname was specified, this environment variable contains it.
|
||||
.It Ev NAME
|
||||
Contains the name of this tinc daemon.
|
||||
.It Ev DEVICE
|
||||
Contains the name of the virtual network device that tinc uses.
|
||||
.It Ev INTERFACE
|
||||
Contains the name of the virtual network interface that tinc uses.
|
||||
This should be used for commands like
|
||||
.Pa ifconfig .
|
||||
.It Ev NODE
|
||||
When a host becomes (un)reachable, this is set to its name.
|
||||
If a subnet becomes (un)reachable, this is set to the owner of that subnet.
|
||||
.It Ev REMOTEADDRESS
|
||||
When a host becomes (un)reachable, this is set to its real address.
|
||||
.It Ev REMOTEPORT
|
||||
When a host becomes (un)reachable, this is set to the port number it uses for communication with other tinc daemons.
|
||||
.It Ev SUBNET
|
||||
When a subnet becomes (un)reachable, this is set to the subnet.
|
||||
.It Ev WEIGHT
|
||||
When a subnet becomes (un)reachable, this is set to the subnet weight.
|
||||
.El
|
||||
.Pp
|
||||
Do not forget that under UNIX operating systems, you have to make the scripts executable, using the command
|
||||
.Nm chmod Li a+x Pa script .
|
||||
.Sh FILES
|
||||
The most important files are:
|
||||
.Bl -tag -width indent
|
||||
.It Pa @sysconfdir@/tinc/
|
||||
The top directory for configuration files.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc.conf
|
||||
The default name of the server configuration file for net
|
||||
.Ar NETNAME .
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /conf.d/
|
||||
Optional directory from which any *.conf file will be loaded
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /hosts/
|
||||
Host configuration files are kept in this directory.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-up
|
||||
If an executable file with this name exists,
|
||||
it will be executed right after the tinc daemon has connected to the virtual network device.
|
||||
It can be used to set up the corresponding network interface.
|
||||
.It Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /tinc-down
|
||||
If an executable file with this name exists,
|
||||
it will be executed right before the tinc daemon is going to close
|
||||
its connection to the virtual network device.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr tincd 8 ,
|
||||
.Pa https://www.tinc-vpn.org/ ,
|
||||
.Pa http://www.tldp.org/LDP/nag2/ .
|
||||
.Pp
|
||||
The full documentation for
|
||||
.Nm tinc
|
||||
is maintained as a Texinfo manual.
|
||||
If the info and tinc programs are properly installed at your site, the command
|
||||
.Ic info tinc
|
||||
should give you access to the complete manual.
|
||||
.Pp
|
||||
.Nm tinc
|
||||
comes with ABSOLUTELY NO WARRANTY.
|
||||
This is free software, and you are welcome to redistribute it under certain conditions;
|
||||
see the file COPYING for details.
|
||||
2773
doc/tinc.info
Normal file
2773
doc/tinc.info
Normal file
File diff suppressed because it is too large
Load diff
2662
doc/tinc.texi
Normal file
2662
doc/tinc.texi
Normal file
File diff suppressed because it is too large
Load diff
226
doc/tincd.8.in
Normal file
226
doc/tincd.8.in
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
.Dd 2014-05-11
|
||||
.Dt TINCD 8
|
||||
.\" Manual page created by:
|
||||
.\" Ivo Timmermans
|
||||
.\" Guus Sliepen <guus@tinc-vpn.org>
|
||||
.Sh NAME
|
||||
.Nm tincd
|
||||
.Nd tinc VPN daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl cdDkKnoLRU
|
||||
.Op Fl -config Ns = Ns Ar DIR
|
||||
.Op Fl -no-detach
|
||||
.Op Fl -debug Ns Op = Ns Ar LEVEL
|
||||
.Op Fl -kill Ns Op = Ns Ar SIGNAL
|
||||
.Op Fl -net Ns = Ns Ar NETNAME
|
||||
.Op Fl -generate-keys Ns Op = Ns Ar BITS
|
||||
.Op Fl -option Ns = Ns Ar [HOST.]KEY=VALUE
|
||||
.Op Fl -mlock
|
||||
.Op Fl -logfile Ns Op = Ns Ar FILE
|
||||
.Op Fl -pidfile Ns = Ns Ar FILE
|
||||
.Op Fl -bypass-security
|
||||
.Op Fl -chroot
|
||||
.Op Fl -user Ns = Ns Ar USER
|
||||
.Op Fl -help
|
||||
.Op Fl -version
|
||||
.Sh DESCRIPTION
|
||||
This is the daemon of tinc, a secure virtual private network (VPN) project.
|
||||
When started,
|
||||
.Nm
|
||||
will read it's configuration file to determine what virtual subnets it has to serve
|
||||
and to what other tinc daemons it should connect.
|
||||
It will connect to the tun/tap device
|
||||
and set up a socket for incoming connections.
|
||||
Optionally a script will be executed to further configure the virtual device.
|
||||
If that succeeds,
|
||||
it will detach from the controlling terminal and continue in the background,
|
||||
accepting and setting up connections to other tinc daemons
|
||||
that are part of the virtual private network.
|
||||
Under Windows (not Cygwin) tinc will install itself as a service,
|
||||
which will be restarted automatically after reboots.
|
||||
.Sh OPTIONS
|
||||
.Bl -tag -width indent
|
||||
.It Fl c, -config Ns = Ns Ar DIR
|
||||
Read configuration files from
|
||||
.Ar DIR
|
||||
instead of
|
||||
.Pa @sysconfdir@/tinc/ .
|
||||
.It Fl D, -no-detach
|
||||
Don't fork and detach.
|
||||
This will also disable the automatic restart mechanism for fatal errors.
|
||||
If not mentioned otherwise, this will show log messages on the standard error output.
|
||||
.It Fl d, -debug Ns Op = Ns Ar LEVEL
|
||||
Increase debug level or set it to
|
||||
.Ar LEVEL
|
||||
(see below).
|
||||
.It Fl k, -kill Ns Op = Ns Ar SIGNAL
|
||||
Attempt to kill a running
|
||||
.Nm
|
||||
(optionally with the specified
|
||||
.Ar SIGNAL
|
||||
instead of SIGTERM) and exit.
|
||||
Under Windows (not Cygwin) the optional argument is ignored,
|
||||
the service will always be stopped and removed.
|
||||
.It Fl n, -net Ns = Ns Ar NETNAME
|
||||
Connect to net
|
||||
.Ar NETNAME .
|
||||
This will let tinc read all configuration files from
|
||||
.Pa @sysconfdir@/tinc/ Ar NETNAME .
|
||||
Specifying
|
||||
.Li .
|
||||
for
|
||||
.Ar NETNAME
|
||||
is the same as not specifying any
|
||||
.Ar NETNAME .
|
||||
.It Fl K, -generate-keys Ns Op = Ns Ar BITS
|
||||
Generate public/private RSA keypair and exit.
|
||||
If
|
||||
.Ar BITS
|
||||
is omitted, the default length will be 2048 bits.
|
||||
When saving keys to existing files, tinc will not delete the old keys,
|
||||
you have to remove them manually.
|
||||
.It Fl o, -option Ns = Ns Ar [HOST.]KEY=VALUE
|
||||
Without specifying a
|
||||
.Ar HOST ,
|
||||
this will set server configuration variable
|
||||
.Ar KEY
|
||||
to
|
||||
.Ar VALUE .
|
||||
If specified as
|
||||
.Ar HOST.KEY=VALUE ,
|
||||
this will set the host configuration variable
|
||||
.Ar KEY
|
||||
of the host named
|
||||
.Ar HOST
|
||||
to
|
||||
.Ar VALUE .
|
||||
This option can be used more than once to specify multiple configuration variables.
|
||||
.It Fl L, -mlock
|
||||
Lock tinc into main memory.
|
||||
This will prevent sensitive data like shared private keys to be written to the system swap files/partitions.
|
||||
.It Fl -logfile Ns Op = Ns Ar FILE
|
||||
Write log entries to a file instead of to the system logging facility.
|
||||
If
|
||||
.Ar FILE
|
||||
is omitted, the default is
|
||||
.Pa @localstatedir@/log/tinc. Ns Ar NETNAME Ns Pa .log.
|
||||
.It Fl -pidfile Ns = Ns Ar FILE
|
||||
Write PID to
|
||||
.Ar FILE
|
||||
instead of
|
||||
.Pa @runstatedir@/tinc. Ns Ar NETNAME Ns Pa .pid.
|
||||
Under Windows this option will be ignored.
|
||||
.It Fl -bypass-security
|
||||
Disables encryption and authentication of the meta protocol.
|
||||
Only useful for debugging.
|
||||
.It Fl R, -chroot
|
||||
With this option tinc chroots into the directory where network
|
||||
config is located (@sysconfdir@/tinc/NETNAME if -n option is used,
|
||||
or to the directory specified with -c option) after initialization.
|
||||
.It Fl U, -user Ns = Ns Ar USER
|
||||
setuid to the specified
|
||||
.Ar USER
|
||||
after initialization.
|
||||
.It Fl -help
|
||||
Display short list of options.
|
||||
.It Fl -version
|
||||
Output version information and exit.
|
||||
.El
|
||||
.Sh SIGNALS
|
||||
.Bl -tag -width indent
|
||||
.It ALRM
|
||||
Forces
|
||||
.Nm
|
||||
to try to connect to all uplinks immediately.
|
||||
Usually
|
||||
.Nm
|
||||
attempts to do this itself,
|
||||
but increases the time it waits between the attempts each time it failed,
|
||||
and if
|
||||
.Nm
|
||||
didn't succeed to connect to an uplink the first time after it started,
|
||||
it defaults to the maximum time of 15 minutes.
|
||||
.It HUP
|
||||
Partially rereads configuration files.
|
||||
Connections to hosts whose host config file are removed are closed.
|
||||
New outgoing connections specified in
|
||||
.Pa tinc.conf
|
||||
will be made.
|
||||
If the
|
||||
.Fl -logfile
|
||||
option is used, this will also close and reopen the log file,
|
||||
useful when log rotation is used.
|
||||
.It INT
|
||||
Temporarily increases debug level to 5.
|
||||
Send this signal again to revert to the original level.
|
||||
.It USR1
|
||||
Dumps the connection list to syslog.
|
||||
.It USR2
|
||||
Dumps virtual network device statistics, all known nodes, edges and subnets to syslog.
|
||||
.It WINCH
|
||||
Purges all information remembered about unreachable nodes.
|
||||
.El
|
||||
.Sh DEBUG LEVELS
|
||||
The tinc daemon can send a lot of messages to the syslog.
|
||||
The higher the debug level,
|
||||
the more messages it will log.
|
||||
Each level inherits all messages of the previous level:
|
||||
.Bl -tag -width indent
|
||||
.It 0
|
||||
This will log a message indicating
|
||||
.Nm
|
||||
has started along with a version number.
|
||||
It will also log any serious error.
|
||||
.It 1
|
||||
This will log all connections that are made with other tinc daemons.
|
||||
.It 2
|
||||
This will log status and error messages from scripts and other tinc daemons.
|
||||
.It 3
|
||||
This will log all requests that are exchanged with other tinc daemons. These include
|
||||
authentication, key exchange and connection list updates.
|
||||
.It 4
|
||||
This will log a copy of everything received on the meta socket.
|
||||
.It 5
|
||||
This will log all network traffic over the virtual private network.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width indent
|
||||
.It Pa @sysconfdir@/tinc/
|
||||
Directory containing the configuration files tinc uses.
|
||||
For more information, see
|
||||
.Xr tinc.conf 5 .
|
||||
.It Pa @runstatedir@/tinc. Ns Ar NETNAME Ns Pa .pid
|
||||
The PID of the currently running
|
||||
.Nm
|
||||
is stored in this file.
|
||||
.El
|
||||
.Sh BUGS
|
||||
The
|
||||
.Va BindToInterface
|
||||
option may not work correctly.
|
||||
.Pp
|
||||
.Sy The cryptography in tinc is not well tested yet. Use it at your own risk!
|
||||
.Pp
|
||||
If you find any bugs, report them to tinc@tinc-vpn.org.
|
||||
.Sh TODO
|
||||
A lot, especially security auditing.
|
||||
.Sh SEE ALSO
|
||||
.Xr tinc.conf 5 ,
|
||||
.Pa https://www.tinc-vpn.org/ ,
|
||||
.Pa http://www.cabal.org/ .
|
||||
.Pp
|
||||
The full documentation for tinc is maintained as a Texinfo manual.
|
||||
If the info and tinc programs are properly installed at your site,
|
||||
the command
|
||||
.Ic info tinc
|
||||
should give you access to the complete manual.
|
||||
.Pp
|
||||
tinc comes with ABSOLUTELY NO WARRANTY.
|
||||
This is free software, and you are welcome to redistribute it under certain conditions;
|
||||
see the file COPYING for details.
|
||||
.Sh AUTHORS
|
||||
.An "Ivo Timmermans"
|
||||
.An "Guus Sliepen" Aq guus@tinc-vpn.org
|
||||
.Pp
|
||||
And thanks to many others for their contributions to tinc!
|
||||
5
doc/tincinclude.texi
Normal file
5
doc/tincinclude.texi
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
@set VERSION 1.0.37
|
||||
@set PACKAGE tinc
|
||||
@set sysconfdir /usr/local/etc
|
||||
@set localstatedir /usr/local/var
|
||||
@set runstatedir /usr/local/var/run
|
||||
5
doc/tincinclude.texi.in
Normal file
5
doc/tincinclude.texi.in
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
@set VERSION @VERSION@
|
||||
@set PACKAGE @PACKAGE@
|
||||
@set sysconfdir @sysconfdir@
|
||||
@set localstatedir @localstatedir@
|
||||
@set runstatedir @runstatedir@
|
||||
541
install-sh
Executable file
541
install-sh
Executable file
|
|
@ -0,0 +1,541 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2025-06-18.21; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
# Create dirs (including intermediate dirs) using mode 755.
|
||||
# This is like GNU 'install' as of coreutils 8.32 (2020).
|
||||
mkdir_umask=22
|
||||
|
||||
backupsuffix=
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-p pass -p to $cpprog.
|
||||
-s $stripprog installed files.
|
||||
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
|
||||
By default, rm is invoked with -f; when overridden with RMPROG,
|
||||
it's up to you to specify -f if you want it.
|
||||
|
||||
If -S is not specified, no backups are attempted.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
GNU Automake home page: <https://www.gnu.org/software/automake/>.
|
||||
General help using GNU software: <https://www.gnu.org/gethelp/>."
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-p) cpprog="$cpprog -p";;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-S) backupsuffix="$2"
|
||||
shift;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 (GNU Automake) $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
# Don't chown directories that already exist.
|
||||
if test $dstdir_status = 0; then
|
||||
chowncmd=""
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dstbase=`basename "$src"`
|
||||
case $dst in
|
||||
*/) dst=$dst$dstbase;;
|
||||
*) dst=$dst/$dstbase;;
|
||||
esac
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
case $dstdir in
|
||||
*/) dstdirslash=$dstdir;;
|
||||
*) dstdirslash=$dstdir/;;
|
||||
esac
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
# The $RANDOM variable is not portable (e.g., dash). Use it
|
||||
# here however when possible just to lower collision chance.
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
|
||||
trap '
|
||||
ret=$?
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
|
||||
exit $ret
|
||||
' 0
|
||||
|
||||
# Because "mkdir -p" follows existing symlinks and we likely work
|
||||
# directly in world-writable /tmp, make sure that the '$tmpdir'
|
||||
# directory is successfully created first before we actually test
|
||||
# 'mkdir -p'.
|
||||
if (umask $mkdir_umask &&
|
||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibility with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
test_tmpdir="$tmpdir/a"
|
||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=${dstdirslash}_inst.$$_
|
||||
rmtmp=${dstdirslash}_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask &&
|
||||
{ test -z "$stripcmd" || {
|
||||
# Create $dsttmp read-write so that cp doesn't create it read-only,
|
||||
# which would cause strip to fail.
|
||||
if test -z "$doit"; then
|
||||
: >"$dsttmp" # No need to fork-exec 'touch'.
|
||||
else
|
||||
$doit touch "$dsttmp"
|
||||
fi
|
||||
}
|
||||
} &&
|
||||
$doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# If $backupsuffix is set, and the file being installed
|
||||
# already exists, attempt a backup. Don't worry if it fails,
|
||||
# e.g., if mv doesn't support -f.
|
||||
if test -n "$backupsuffix" && test -f "$dst"; then
|
||||
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp nil t)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%Y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
25
m4/attribute.m4
Normal file
25
m4/attribute.m4
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
dnl Check to find out whether function attributes are supported.
|
||||
dnl If they are not, #define them to be nothing.
|
||||
|
||||
AC_DEFUN([tinc_ATTRIBUTE],
|
||||
[
|
||||
AC_CACHE_CHECK([for working $1 attribute], tinc_cv_attribute_$1,
|
||||
[
|
||||
tempcflags="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Wall -Werror"
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_SOURCE(
|
||||
[void *test(void) __attribute__ (($1));
|
||||
void *test(void) { return (void *)0; }
|
||||
],
|
||||
)],
|
||||
[tinc_cv_attribute_$1=yes],
|
||||
[tinc_cv_attribute_$1=no]
|
||||
)
|
||||
CFLAGS="$tempcflags"
|
||||
])
|
||||
|
||||
if test ${tinc_cv_attribute_$1} = no; then
|
||||
AC_DEFINE([$1], [], [Defined if the $1 attribute is not supported.])
|
||||
fi
|
||||
])
|
||||
69
m4/ax_append_flag.m4
Normal file
69
m4/ax_append_flag.m4
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
|
||||
# added in between.
|
||||
#
|
||||
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
|
||||
# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
|
||||
# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
|
||||
# FLAG.
|
||||
#
|
||||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 2
|
||||
|
||||
AC_DEFUN([AX_APPEND_FLAG],
|
||||
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
|
||||
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl
|
||||
AS_VAR_SET_IF(FLAGS,
|
||||
[case " AS_VAR_GET(FLAGS) " in
|
||||
*" $1 "*)
|
||||
AC_RUN_LOG([: FLAGS already contains $1])
|
||||
;;
|
||||
*)
|
||||
AC_RUN_LOG([: FLAGS="$FLAGS $1"])
|
||||
AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"])
|
||||
;;
|
||||
esac],
|
||||
[AS_VAR_SET(FLAGS,["$1"])])
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])dnl AX_APPEND_FLAG
|
||||
122
m4/ax_cflags_warn_all.m4
Normal file
122
m4/ax_cflags_warn_all.m4
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])]
|
||||
# AX_CXXFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])]
|
||||
# AX_FCFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])]
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Try to find a compiler option that enables most reasonable warnings.
|
||||
#
|
||||
# For the GNU compiler it will be -Wall (and -ansi -pedantic) The result
|
||||
# is added to the shellvar being CFLAGS, CXXFLAGS, or FCFLAGS by default.
|
||||
#
|
||||
# Currently this macro knows about the GCC, Solaris, Digital Unix, AIX,
|
||||
# HP-UX, IRIX, NEC SX-5 (Super-UX 10), Cray J90 (Unicos 10.0.0.8), and
|
||||
# Intel compilers. For a given compiler, the Fortran flags are much more
|
||||
# experimental than their C equivalents.
|
||||
#
|
||||
# - $1 shell-variable-to-add-to : CFLAGS, CXXFLAGS, or FCFLAGS
|
||||
# - $2 add-value-if-not-found : nothing
|
||||
# - $3 action-if-found : add value to shellvariable
|
||||
# - $4 action-if-not-found : nothing
|
||||
#
|
||||
# NOTE: These macros depend on AX_APPEND_FLAG.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2010 Rhys Ulerich <rhys.ulerich@gmail.com>
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 15
|
||||
|
||||
AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl
|
||||
AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl
|
||||
AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl
|
||||
AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
|
||||
VAR,[VAR="no, unknown"
|
||||
ac_save_[]FLAGS="$[]FLAGS"
|
||||
for ac_arg dnl
|
||||
in "-warn all % -warn all" dnl Intel
|
||||
"-pedantic % -Wall" dnl GCC
|
||||
"-xstrconst % -v" dnl Solaris C
|
||||
"-std1 % -verbose -w0 -warnprotos" dnl Digital Unix
|
||||
"-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
|
||||
"-ansi -ansiE % -fullwarn" dnl IRIX
|
||||
"+ESlit % +w1" dnl HP-UX C
|
||||
"-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10)
|
||||
"-h conform % -h msglevel 2" dnl Cray C (Unicos)
|
||||
#
|
||||
do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
|
||||
[VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
|
||||
done
|
||||
FLAGS="$ac_save_[]FLAGS"
|
||||
])
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
|
||||
case ".$VAR" in
|
||||
.ok|.ok,*) m4_ifvaln($3,$3) ;;
|
||||
.|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;;
|
||||
*) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;;
|
||||
esac
|
||||
AS_VAR_POPDEF([VAR])dnl
|
||||
])dnl AX_FLAGS_WARN_ALL
|
||||
dnl implementation tactics:
|
||||
dnl the for-argument contains a list of options. The first part of
|
||||
dnl these does only exist to detect the compiler - usually it is
|
||||
dnl a global option to enable -ansi or -extrawarnings. All other
|
||||
dnl compilers will fail about it. That was needed since a lot of
|
||||
dnl compilers will give false positives for some option-syntax
|
||||
dnl like -Woption or -Xoption as they think of it is a pass-through
|
||||
dnl to later compile stages or something. The "%" is used as a
|
||||
dnl delimiter. A non-option comment can be given after "%%" marks
|
||||
dnl which will be shown but not added to the respective C/CXXFLAGS.
|
||||
|
||||
AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl
|
||||
AC_LANG_PUSH([C])
|
||||
AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
|
||||
AC_LANG_POP([C])
|
||||
])
|
||||
|
||||
AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl
|
||||
AC_LANG_PUSH([C++])
|
||||
AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
|
||||
AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl
|
||||
AC_LANG_PUSH([Fortran])
|
||||
AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
|
||||
AC_LANG_POP([Fortran])
|
||||
])
|
||||
72
m4/ax_check_compile_flag.m4
Normal file
72
m4/ax_check_compile_flag.m4
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check whether the given FLAG works with the current language's compiler
|
||||
# or gives an error. (Warnings, however, are ignored)
|
||||
#
|
||||
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
|
||||
# success/failure.
|
||||
#
|
||||
# If EXTRA-FLAGS is defined, it is added to the current language's default
|
||||
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
|
||||
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
|
||||
# force the compiler to issue an error when a bad flag is given.
|
||||
#
|
||||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
|
||||
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 2
|
||||
|
||||
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
|
||||
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
|
||||
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
|
||||
AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
])dnl AX_CHECK_COMPILE_FLAGS
|
||||
71
m4/ax_check_link_flag.m4
Normal file
71
m4/ax_check_link_flag.m4
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check whether the given FLAG works with the linker or gives an error.
|
||||
# (Warnings, however, are ignored)
|
||||
#
|
||||
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
|
||||
# success/failure.
|
||||
#
|
||||
# If EXTRA-FLAGS is defined, it is added to the linker's default flags
|
||||
# when the check is done. The check is thus made with the flags: "LDFLAGS
|
||||
# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
|
||||
# issue an error when a bad flag is given.
|
||||
#
|
||||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
|
||||
# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 2
|
||||
|
||||
AC_DEFUN([AX_CHECK_LINK_FLAG],
|
||||
[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS $4 $1"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM()],
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
LDFLAGS=$ax_check_save_flags])
|
||||
AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
])dnl AX_CHECK_LINK_FLAGS
|
||||
37
m4/ax_require_defined.m4
Normal file
37
m4/ax_require_defined.m4
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_require_defined.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_REQUIRE_DEFINED(MACRO)
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
|
||||
# been defined and thus are available for use. This avoids random issues
|
||||
# where a macro isn't expanded. Instead the configure script emits a
|
||||
# non-fatal:
|
||||
#
|
||||
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
|
||||
#
|
||||
# It's like AC_REQUIRE except it doesn't expand the required macro.
|
||||
#
|
||||
# Here's an example:
|
||||
#
|
||||
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 1
|
||||
|
||||
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
|
||||
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
|
||||
])dnl AX_REQUIRE_DEFINED
|
||||
47
m4/lzo.m4
Normal file
47
m4/lzo.m4
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
dnl Check to find the lzo headers/libraries
|
||||
|
||||
AC_DEFUN([tinc_LZO],
|
||||
[
|
||||
AC_ARG_ENABLE([lzo],
|
||||
AS_HELP_STRING([--disable-lzo], [disable lzo compression support]))
|
||||
AS_IF([test "x$enable_lzo" != "xno"], [
|
||||
AC_DEFINE(HAVE_LZO, 1, [enable lzo compression support])
|
||||
AC_ARG_WITH(lzo,
|
||||
AS_HELP_STRING([--with-lzo=DIR], [lzo base directory, or:]),
|
||||
[lzo="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(lzo-include,
|
||||
AS_HELP_STRING([--with-lzo-include=DIR], [lzo headers directory]),
|
||||
[lzo_include="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(lzo-lib,
|
||||
AS_HELP_STRING([--with-lzo-lib=DIR], [lzo library directory]),
|
||||
[lzo_lib="$withval"
|
||||
LDFLAGS="$LDFLAGS -L$withval"]
|
||||
)
|
||||
|
||||
AC_CHECK_LIB(lzo2, lzo1x_1_compress,
|
||||
[LIBS="$LIBS -llzo2"],
|
||||
[AC_CHECK_LIB(lzo, lzo1x_1_compress,
|
||||
[LIBS="$LIBS -llzo"],
|
||||
[AC_MSG_ERROR("lzo libraries not found."); break]
|
||||
)]
|
||||
)
|
||||
|
||||
AC_CHECK_HEADERS(lzo/lzo1x.h,
|
||||
[AC_DEFINE(LZO1X_H, [<lzo/lzo1x.h>], [Location of lzo1x.h])],
|
||||
[AC_CHECK_HEADERS(lzo2/lzo1x.h,
|
||||
[AC_DEFINE(LZO1X_H, [<lzo2/lzo1x.h>], [Location of lzo1x.h])],
|
||||
[AC_CHECK_HEADERS(lzo1x.h,
|
||||
[AC_DEFINE(LZO1X_H, [<lzo1x.h>], [Location of lzo1x.h])],
|
||||
[AC_MSG_ERROR("lzo header files not found."); break]
|
||||
)]
|
||||
)]
|
||||
)
|
||||
])
|
||||
])
|
||||
53
m4/openssl.m4
Normal file
53
m4/openssl.m4
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
dnl Check to find the LibreSSL/OpenSSL headers/libraries
|
||||
|
||||
AC_DEFUN([tinc_OPENSSL],
|
||||
[
|
||||
case $host_os in
|
||||
*mingw*)
|
||||
;;
|
||||
*)
|
||||
AC_CHECK_FUNC(dlopen,
|
||||
[],
|
||||
[AC_CHECK_LIB(dl, dlopen,
|
||||
[LIBS="$LIBS -ldl"],
|
||||
[AC_MSG_ERROR([LibreSSL/OpenSSL depends on libdl.]); break]
|
||||
)]
|
||||
)
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_ARG_WITH(openssl,
|
||||
AS_HELP_STRING([--with-openssl=DIR], [LibreSSL/OpenSSL base directory, or:]),
|
||||
[openssl="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(openssl-include,
|
||||
AS_HELP_STRING([--with-openssl-include=DIR], [LibreSSL/OpenSSL headers directory (without trailing /openssl)]),
|
||||
[openssl_include="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(openssl-lib,
|
||||
AS_HELP_STRING([--with-openssl-lib=DIR], [LibreSSL/OpenSSL library directory]),
|
||||
[openssl_lib="$withval"
|
||||
LDFLAGS="$LDFLAGS -L$withval"]
|
||||
)
|
||||
|
||||
AC_CHECK_HEADERS([openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h],
|
||||
[],
|
||||
[AC_MSG_ERROR([LibreSSL/OpenSSL header files not found.]); break]
|
||||
)
|
||||
|
||||
AC_CHECK_HEADERS([openssl/param_build.h])
|
||||
|
||||
AC_CHECK_LIB(crypto, OPENSSL_init_crypto,
|
||||
[LIBS="-lcrypto $LIBS"],
|
||||
[AC_MSG_ERROR([LibreSSL/OpenSSL libraries not found.])]
|
||||
)
|
||||
|
||||
AC_CHECK_DECLS([EVP_RSA_gen], [], [], [#include <openssl/rsa.h>])
|
||||
|
||||
AC_DEFINE(HAVE_OPENSSL, 1, [enable OpenSSL support])
|
||||
])
|
||||
38
m4/zlib.m4
Normal file
38
m4/zlib.m4
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
dnl Check to find the zlib headers/libraries
|
||||
|
||||
AC_DEFUN([tinc_ZLIB],
|
||||
[
|
||||
AC_ARG_ENABLE([zlib],
|
||||
AS_HELP_STRING([--disable-zlib], [disable zlib compression support]))
|
||||
AS_IF([test "x$enable_zlib" != "xno"], [
|
||||
AC_DEFINE(HAVE_ZLIB, 1, [have zlib compression support])
|
||||
AC_ARG_WITH(zlib,
|
||||
AS_HELP_STRING([--with-zlib=DIR], [zlib base directory, or:]),
|
||||
[zlib="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(zlib-include,
|
||||
AS_HELP_STRING([--with-zlib-include=DIR], [zlib headers directory]),
|
||||
[zlib_include="$withval"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(zlib-lib,
|
||||
AS_HELP_STRING([--with-zlib-lib=DIR], [zlib library directory]),
|
||||
[zlib_lib="$withval"
|
||||
LDFLAGS="$LDFLAGS -L$withval"]
|
||||
)
|
||||
|
||||
AC_CHECK_HEADERS(zlib.h,
|
||||
[],
|
||||
[AC_MSG_ERROR("zlib header files not found."); break]
|
||||
)
|
||||
|
||||
AC_CHECK_LIB(z, compress2,
|
||||
[LIBS="$LIBS -lz"],
|
||||
[AC_MSG_ERROR("zlib libraries not found.")]
|
||||
)
|
||||
])
|
||||
])
|
||||
236
missing
Executable file
236
missing
Executable file
|
|
@ -0,0 +1,236 @@
|
|||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU and other programs.
|
||||
|
||||
scriptversion=2025-06-18.21; # UTC
|
||||
|
||||
# shellcheck disable=SC2006,SC2268 # we must support pre-POSIX shells
|
||||
|
||||
# Copyright (C) 1996-2025 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# 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, 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, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autogen autoheader autom4te automake autoreconf
|
||||
bison flex help2man lex makeinfo perl yacc
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
GNU Automake home page: <https://www.gnu.org/software/automake/>.
|
||||
General help using GNU software: <https://www.gnu.org/gethelp/>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing (GNU Automake) $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=https://www.perl.org/
|
||||
flex_URL=https://github.com/westes/flex
|
||||
gnu_software_URL=https://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake|autoreconf)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
*)
|
||||
:
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
autoheader_deps="'acconfig.h'"
|
||||
automake_deps="'Makefile.am'"
|
||||
aclocal_deps="'acinclude.m4'"
|
||||
case $normalized_program in
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified $aclocal_deps or"
|
||||
echo "$configure_deps."
|
||||
;;
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified $configure_deps."
|
||||
;;
|
||||
autogen*)
|
||||
echo "You should only need it if you modified a '.def' or '.tpl' file."
|
||||
echo "You may want to install the GNU AutoGen package:"
|
||||
echo "<$gnu_software_URL/autogen/>"
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified $autoheader_deps or"
|
||||
echo "$configure_deps."
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified $automake_deps or"
|
||||
echo "$configure_deps."
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
;;
|
||||
autoreconf*)
|
||||
echo "You should only need it if you modified $aclocal_deps or"
|
||||
echo "$automake_deps or $autoheader_deps or $automake_deps or"
|
||||
echo "$configure_deps."
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
perl*)
|
||||
echo "You should only need it to run GNU Autoconf, GNU Automake, "
|
||||
echo " assorted other tools, or if you modified a Perl source file."
|
||||
echo "You may want to install the Perl 5 language interpreter:"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
program_details "$normalized_program"
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp nil t)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%Y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
89
src/Makefile.am
Normal file
89
src/Makefile.am
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
## Produce this file with automake to get Makefile.in
|
||||
|
||||
sbin_PROGRAMS = tincd
|
||||
|
||||
tincd_SOURCES = \
|
||||
have.h \
|
||||
system.h \
|
||||
avl_tree.c avl_tree.h \
|
||||
conf.c conf.h \
|
||||
connection.c connection.h \
|
||||
device.h \
|
||||
dropin.c dropin.h \
|
||||
dummy_device.c \
|
||||
edge.c edge.h \
|
||||
ethernet.h \
|
||||
event.c event.h \
|
||||
fake-getaddrinfo.c fake-getaddrinfo.h \
|
||||
fake-getnameinfo.c fake-getnameinfo.h \
|
||||
graph.c graph.h \
|
||||
ipv4.h \
|
||||
ipv6.h \
|
||||
list.c list.h \
|
||||
logger.c logger.h \
|
||||
meta.c meta.h \
|
||||
multicast_device.c \
|
||||
net.c net.h \
|
||||
net_packet.c \
|
||||
net_setup.c \
|
||||
net_socket.c \
|
||||
netutl.c netutl.h \
|
||||
node.c node.h \
|
||||
pidfile.c pidfile.h \
|
||||
process.c process.h \
|
||||
protocol.c protocol.h \
|
||||
protocol_auth.c \
|
||||
protocol_edge.c \
|
||||
protocol_misc.c \
|
||||
protocol_key.c \
|
||||
protocol_subnet.c \
|
||||
proxy.c proxy.h \
|
||||
raw_socket_device.c \
|
||||
route.c route.h \
|
||||
subnet.c subnet.h \
|
||||
tincd.c \
|
||||
utils.c utils.h \
|
||||
xalloc.h
|
||||
|
||||
if !GETOPT
|
||||
tincd_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
endif
|
||||
|
||||
if LINUX
|
||||
tincd_SOURCES += linux/device.c
|
||||
endif
|
||||
|
||||
if BSD
|
||||
tincd_SOURCES += bsd/device.c
|
||||
if TUNEMU
|
||||
tincd_SOURCES += bsd/tunemu.c bsd/tunemu.h
|
||||
endif
|
||||
endif
|
||||
|
||||
if SOLARIS
|
||||
tincd_SOURCES += solaris/device.c
|
||||
endif
|
||||
|
||||
if MINGW
|
||||
tincd_SOURCES += mingw/device.c mingw/common.h
|
||||
endif
|
||||
|
||||
if CYGWIN
|
||||
tincd_SOURCES += cygwin/device.c
|
||||
endif
|
||||
|
||||
if UML
|
||||
tincd_SOURCES += uml_device.c
|
||||
endif
|
||||
|
||||
if VDE
|
||||
tincd_SOURCES += vde_device.c
|
||||
endif
|
||||
|
||||
if TUNEMU
|
||||
LIBS += -lpcap
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DRUNSTATEDIR=\"$(runstatedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -I $(abs_top_builddir)/
|
||||
906
src/Makefile.in
Normal file
906
src/Makefile.in
Normal file
|
|
@ -0,0 +1,906 @@
|
|||
# Makefile.in generated by automake 1.18.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2025 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
am__rm_f = rm -f $(am__rm_f_notfound)
|
||||
am__rm_rf = rm -rf $(am__rm_f_notfound)
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
sbin_PROGRAMS = tincd$(EXEEXT)
|
||||
@GETOPT_FALSE@am__append_1 = \
|
||||
@GETOPT_FALSE@ getopt.c getopt.h \
|
||||
@GETOPT_FALSE@ getopt1.c
|
||||
|
||||
@LINUX_TRUE@am__append_2 = linux/device.c
|
||||
@BSD_TRUE@am__append_3 = bsd/device.c
|
||||
@BSD_TRUE@@TUNEMU_TRUE@am__append_4 = bsd/tunemu.c bsd/tunemu.h
|
||||
@SOLARIS_TRUE@am__append_5 = solaris/device.c
|
||||
@MINGW_TRUE@am__append_6 = mingw/device.c mingw/common.h
|
||||
@CYGWIN_TRUE@am__append_7 = cygwin/device.c
|
||||
@UML_TRUE@am__append_8 = uml_device.c
|
||||
@VDE_TRUE@am__append_9 = vde_device.c
|
||||
@TUNEMU_TRUE@am__append_10 = -lpcap
|
||||
subdir = src
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/ax_append_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
|
||||
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_check_link_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_require_defined.m4 $(top_srcdir)/m4/lzo.m4 \
|
||||
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__installdirs = "$(DESTDIR)$(sbindir)"
|
||||
PROGRAMS = $(sbin_PROGRAMS)
|
||||
am__tincd_SOURCES_DIST = have.h system.h avl_tree.c avl_tree.h conf.c \
|
||||
conf.h connection.c connection.h device.h dropin.c dropin.h \
|
||||
dummy_device.c edge.c edge.h ethernet.h event.c event.h \
|
||||
fake-getaddrinfo.c fake-getaddrinfo.h fake-getnameinfo.c \
|
||||
fake-getnameinfo.h graph.c graph.h ipv4.h ipv6.h list.c list.h \
|
||||
logger.c logger.h meta.c meta.h multicast_device.c net.c net.h \
|
||||
net_packet.c net_setup.c net_socket.c netutl.c netutl.h node.c \
|
||||
node.h pidfile.c pidfile.h process.c process.h protocol.c \
|
||||
protocol.h protocol_auth.c protocol_edge.c protocol_misc.c \
|
||||
protocol_key.c protocol_subnet.c proxy.c proxy.h \
|
||||
raw_socket_device.c route.c route.h subnet.c subnet.h tincd.c \
|
||||
utils.c utils.h xalloc.h getopt.c getopt.h getopt1.c \
|
||||
linux/device.c bsd/device.c bsd/tunemu.c bsd/tunemu.h \
|
||||
solaris/device.c mingw/device.c mingw/common.h cygwin/device.c \
|
||||
uml_device.c vde_device.c
|
||||
@GETOPT_FALSE@am__objects_1 = getopt.$(OBJEXT) getopt1.$(OBJEXT)
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
@LINUX_TRUE@am__objects_2 = linux/device.$(OBJEXT)
|
||||
@BSD_TRUE@am__objects_3 = bsd/device.$(OBJEXT)
|
||||
@BSD_TRUE@@TUNEMU_TRUE@am__objects_4 = bsd/tunemu.$(OBJEXT)
|
||||
@SOLARIS_TRUE@am__objects_5 = solaris/device.$(OBJEXT)
|
||||
@MINGW_TRUE@am__objects_6 = mingw/device.$(OBJEXT)
|
||||
@CYGWIN_TRUE@am__objects_7 = cygwin/device.$(OBJEXT)
|
||||
@UML_TRUE@am__objects_8 = uml_device.$(OBJEXT)
|
||||
@VDE_TRUE@am__objects_9 = vde_device.$(OBJEXT)
|
||||
am_tincd_OBJECTS = avl_tree.$(OBJEXT) conf.$(OBJEXT) \
|
||||
connection.$(OBJEXT) dropin.$(OBJEXT) dummy_device.$(OBJEXT) \
|
||||
edge.$(OBJEXT) event.$(OBJEXT) fake-getaddrinfo.$(OBJEXT) \
|
||||
fake-getnameinfo.$(OBJEXT) graph.$(OBJEXT) list.$(OBJEXT) \
|
||||
logger.$(OBJEXT) meta.$(OBJEXT) multicast_device.$(OBJEXT) \
|
||||
net.$(OBJEXT) net_packet.$(OBJEXT) net_setup.$(OBJEXT) \
|
||||
net_socket.$(OBJEXT) netutl.$(OBJEXT) node.$(OBJEXT) \
|
||||
pidfile.$(OBJEXT) process.$(OBJEXT) protocol.$(OBJEXT) \
|
||||
protocol_auth.$(OBJEXT) protocol_edge.$(OBJEXT) \
|
||||
protocol_misc.$(OBJEXT) protocol_key.$(OBJEXT) \
|
||||
protocol_subnet.$(OBJEXT) proxy.$(OBJEXT) \
|
||||
raw_socket_device.$(OBJEXT) route.$(OBJEXT) subnet.$(OBJEXT) \
|
||||
tincd.$(OBJEXT) utils.$(OBJEXT) $(am__objects_1) \
|
||||
$(am__objects_2) $(am__objects_3) $(am__objects_4) \
|
||||
$(am__objects_5) $(am__objects_6) $(am__objects_7) \
|
||||
$(am__objects_8) $(am__objects_9)
|
||||
tincd_OBJECTS = $(am_tincd_OBJECTS)
|
||||
tincd_LDADD = $(LDADD)
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
DEFAULT_INCLUDES =
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__maybe_remake_depfiles = depfiles
|
||||
am__depfiles_remade = ./$(DEPDIR)/avl_tree.Po ./$(DEPDIR)/conf.Po \
|
||||
./$(DEPDIR)/connection.Po ./$(DEPDIR)/dropin.Po \
|
||||
./$(DEPDIR)/dummy_device.Po ./$(DEPDIR)/edge.Po \
|
||||
./$(DEPDIR)/event.Po ./$(DEPDIR)/fake-getaddrinfo.Po \
|
||||
./$(DEPDIR)/fake-getnameinfo.Po ./$(DEPDIR)/getopt.Po \
|
||||
./$(DEPDIR)/getopt1.Po ./$(DEPDIR)/graph.Po \
|
||||
./$(DEPDIR)/list.Po ./$(DEPDIR)/logger.Po ./$(DEPDIR)/meta.Po \
|
||||
./$(DEPDIR)/multicast_device.Po ./$(DEPDIR)/net.Po \
|
||||
./$(DEPDIR)/net_packet.Po ./$(DEPDIR)/net_setup.Po \
|
||||
./$(DEPDIR)/net_socket.Po ./$(DEPDIR)/netutl.Po \
|
||||
./$(DEPDIR)/node.Po ./$(DEPDIR)/pidfile.Po \
|
||||
./$(DEPDIR)/process.Po ./$(DEPDIR)/protocol.Po \
|
||||
./$(DEPDIR)/protocol_auth.Po ./$(DEPDIR)/protocol_edge.Po \
|
||||
./$(DEPDIR)/protocol_key.Po ./$(DEPDIR)/protocol_misc.Po \
|
||||
./$(DEPDIR)/protocol_subnet.Po ./$(DEPDIR)/proxy.Po \
|
||||
./$(DEPDIR)/raw_socket_device.Po ./$(DEPDIR)/route.Po \
|
||||
./$(DEPDIR)/subnet.Po ./$(DEPDIR)/tincd.Po \
|
||||
./$(DEPDIR)/uml_device.Po ./$(DEPDIR)/utils.Po \
|
||||
./$(DEPDIR)/vde_device.Po bsd/$(DEPDIR)/device.Po \
|
||||
bsd/$(DEPDIR)/tunemu.Po cygwin/$(DEPDIR)/device.Po \
|
||||
linux/$(DEPDIR)/device.Po mingw/$(DEPDIR)/device.Po \
|
||||
solaris/$(DEPDIR)/device.Po
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CC_1 =
|
||||
CCLD = $(CC)
|
||||
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(tincd_SOURCES)
|
||||
DIST_SOURCES = $(am__tincd_SOURCES_DIST)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CSCOPE = @CSCOPE@
|
||||
CTAGS = @CTAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
ETAGS = @ETAGS@
|
||||
EXEEXT = @EXEEXT@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@ $(am__append_10)
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
OBJEXT = @OBJEXT@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__rm_f_notfound = @am__rm_f_notfound@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
am__xargs_n = @am__xargs_n@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
systemd_path = @systemd_path@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
tincd_SOURCES = have.h system.h avl_tree.c avl_tree.h conf.c conf.h \
|
||||
connection.c connection.h device.h dropin.c dropin.h \
|
||||
dummy_device.c edge.c edge.h ethernet.h event.c event.h \
|
||||
fake-getaddrinfo.c fake-getaddrinfo.h fake-getnameinfo.c \
|
||||
fake-getnameinfo.h graph.c graph.h ipv4.h ipv6.h list.c list.h \
|
||||
logger.c logger.h meta.c meta.h multicast_device.c net.c net.h \
|
||||
net_packet.c net_setup.c net_socket.c netutl.c netutl.h node.c \
|
||||
node.h pidfile.c pidfile.h process.c process.h protocol.c \
|
||||
protocol.h protocol_auth.c protocol_edge.c protocol_misc.c \
|
||||
protocol_key.c protocol_subnet.c proxy.c proxy.h \
|
||||
raw_socket_device.c route.c route.h subnet.c subnet.h tincd.c \
|
||||
utils.c utils.h xalloc.h $(am__append_1) $(am__append_2) \
|
||||
$(am__append_3) $(am__append_4) $(am__append_5) \
|
||||
$(am__append_6) $(am__append_7) $(am__append_8) \
|
||||
$(am__append_9)
|
||||
AM_CPPFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DRUNSTATEDIR=\"$(runstatedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -I $(abs_top_builddir)/
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu src/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
install-sbinPROGRAMS: $(sbin_PROGRAMS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed 's/$(EXEEXT)$$//' | \
|
||||
while read p p1; do if test -f $$p \
|
||||
; then echo "$$p"; echo "$$p"; else :; fi; \
|
||||
done | \
|
||||
sed -e 'p;s,.*/,,;n;h' \
|
||||
-e 's|.*|.|' \
|
||||
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
|
||||
sed 'N;N;N;s,\n, ,g' | \
|
||||
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
|
||||
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
|
||||
if ($$2 == $$4) files[d] = files[d] " " $$1; \
|
||||
else { print "f", $$3 "/" $$4, $$1; } } \
|
||||
END { for (d in files) print "f", d, files[d] }' | \
|
||||
while read type dir files; do \
|
||||
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
|
||||
test -z "$$files" || { \
|
||||
echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
|
||||
$(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
|
||||
} \
|
||||
; done
|
||||
|
||||
uninstall-sbinPROGRAMS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
|
||||
files=`for p in $$list; do echo "$$p"; done | \
|
||||
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
|
||||
-e 's/$$/$(EXEEXT)/' \
|
||||
`; \
|
||||
test -n "$$list" || exit 0; \
|
||||
echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
|
||||
cd "$(DESTDIR)$(sbindir)" && $(am__rm_f) $$files
|
||||
|
||||
clean-sbinPROGRAMS:
|
||||
-$(am__rm_f) $(sbin_PROGRAMS)
|
||||
|
||||
installcheck-sbinPROGRAMS: $(sbin_PROGRAMS)
|
||||
bad=0; pid=$$$$; list="$(sbin_PROGRAMS)"; for p in $$list; do \
|
||||
case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \
|
||||
*" $$p "* | *" $(srcdir)/$$p "*) continue;; \
|
||||
esac; \
|
||||
f=`echo "$$p" | \
|
||||
sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
|
||||
for opt in --help --version; do \
|
||||
"$(DESTDIR)$(sbindir)/$$f" $$opt \
|
||||
>c$${pid}_.out 2>c$${pid}_.err </dev/null; \
|
||||
xc=$$?; \
|
||||
if test -n "`cat c$${pid}_.err`"; then \
|
||||
echo "$$f does not support $$opt: error output" 1>&2; \
|
||||
cat c$${pid}_.err 1>&2; \
|
||||
bad=1; \
|
||||
else \
|
||||
if test -z "`cat c$${pid}_.out`"; then \
|
||||
echo "$$f does not support $$opt: no output" 1>&2; \
|
||||
bad=1; \
|
||||
else \
|
||||
if test $$xc != 0; then \
|
||||
echo "$$f does not support $$opt: exit code $$xc" 1>&2; \
|
||||
bad=1; \
|
||||
else \
|
||||
:; \
|
||||
fi; \
|
||||
fi; \
|
||||
fi; \
|
||||
done; \
|
||||
done; rm -f c$${pid}_.???; exit $$bad
|
||||
linux/$(am__dirstamp):
|
||||
@$(MKDIR_P) linux
|
||||
@: >>linux/$(am__dirstamp)
|
||||
linux/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) linux/$(DEPDIR)
|
||||
@: >>linux/$(DEPDIR)/$(am__dirstamp)
|
||||
linux/device.$(OBJEXT): linux/$(am__dirstamp) \
|
||||
linux/$(DEPDIR)/$(am__dirstamp)
|
||||
bsd/$(am__dirstamp):
|
||||
@$(MKDIR_P) bsd
|
||||
@: >>bsd/$(am__dirstamp)
|
||||
bsd/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) bsd/$(DEPDIR)
|
||||
@: >>bsd/$(DEPDIR)/$(am__dirstamp)
|
||||
bsd/device.$(OBJEXT): bsd/$(am__dirstamp) \
|
||||
bsd/$(DEPDIR)/$(am__dirstamp)
|
||||
bsd/tunemu.$(OBJEXT): bsd/$(am__dirstamp) \
|
||||
bsd/$(DEPDIR)/$(am__dirstamp)
|
||||
solaris/$(am__dirstamp):
|
||||
@$(MKDIR_P) solaris
|
||||
@: >>solaris/$(am__dirstamp)
|
||||
solaris/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) solaris/$(DEPDIR)
|
||||
@: >>solaris/$(DEPDIR)/$(am__dirstamp)
|
||||
solaris/device.$(OBJEXT): solaris/$(am__dirstamp) \
|
||||
solaris/$(DEPDIR)/$(am__dirstamp)
|
||||
mingw/$(am__dirstamp):
|
||||
@$(MKDIR_P) mingw
|
||||
@: >>mingw/$(am__dirstamp)
|
||||
mingw/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) mingw/$(DEPDIR)
|
||||
@: >>mingw/$(DEPDIR)/$(am__dirstamp)
|
||||
mingw/device.$(OBJEXT): mingw/$(am__dirstamp) \
|
||||
mingw/$(DEPDIR)/$(am__dirstamp)
|
||||
cygwin/$(am__dirstamp):
|
||||
@$(MKDIR_P) cygwin
|
||||
@: >>cygwin/$(am__dirstamp)
|
||||
cygwin/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) cygwin/$(DEPDIR)
|
||||
@: >>cygwin/$(DEPDIR)/$(am__dirstamp)
|
||||
cygwin/device.$(OBJEXT): cygwin/$(am__dirstamp) \
|
||||
cygwin/$(DEPDIR)/$(am__dirstamp)
|
||||
|
||||
tincd$(EXEEXT): $(tincd_OBJECTS) $(tincd_DEPENDENCIES) $(EXTRA_tincd_DEPENDENCIES)
|
||||
@rm -f tincd$(EXEEXT)
|
||||
$(AM_V_CCLD)$(LINK) $(tincd_OBJECTS) $(tincd_LDADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
-rm -f bsd/*.$(OBJEXT)
|
||||
-rm -f cygwin/*.$(OBJEXT)
|
||||
-rm -f linux/*.$(OBJEXT)
|
||||
-rm -f mingw/*.$(OBJEXT)
|
||||
-rm -f solaris/*.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avl_tree.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dropin.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy_device.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edge.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getaddrinfo.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake-getnameinfo.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/graph.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/meta.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/multicast_device.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_packet.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_setup.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_socket.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netutl.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pidfile.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_auth.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_edge.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_key.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_misc.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol_subnet.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proxy.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw_socket_device.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnet.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tincd.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uml_device.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vde_device.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bsd/$(DEPDIR)/device.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bsd/$(DEPDIR)/tunemu.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@cygwin/$(DEPDIR)/device.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@linux/$(DEPDIR)/device.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@mingw/$(DEPDIR)/device.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@solaris/$(DEPDIR)/device.Po@am__quote@ # am--include-marker
|
||||
|
||||
$(am__depfiles_remade):
|
||||
@$(MKDIR_P) $(@D)
|
||||
@: >>$@
|
||||
|
||||
am--depfiles: $(am__depfiles_remade)
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(PROGRAMS)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(sbindir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-$(am__rm_f) $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES)
|
||||
-$(am__rm_f) bsd/$(DEPDIR)/$(am__dirstamp)
|
||||
-$(am__rm_f) bsd/$(am__dirstamp)
|
||||
-$(am__rm_f) cygwin/$(DEPDIR)/$(am__dirstamp)
|
||||
-$(am__rm_f) cygwin/$(am__dirstamp)
|
||||
-$(am__rm_f) linux/$(DEPDIR)/$(am__dirstamp)
|
||||
-$(am__rm_f) linux/$(am__dirstamp)
|
||||
-$(am__rm_f) mingw/$(DEPDIR)/$(am__dirstamp)
|
||||
-$(am__rm_f) mingw/$(am__dirstamp)
|
||||
-$(am__rm_f) solaris/$(DEPDIR)/$(am__dirstamp)
|
||||
-$(am__rm_f) solaris/$(am__dirstamp)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f ./$(DEPDIR)/avl_tree.Po
|
||||
-rm -f ./$(DEPDIR)/conf.Po
|
||||
-rm -f ./$(DEPDIR)/connection.Po
|
||||
-rm -f ./$(DEPDIR)/dropin.Po
|
||||
-rm -f ./$(DEPDIR)/dummy_device.Po
|
||||
-rm -f ./$(DEPDIR)/edge.Po
|
||||
-rm -f ./$(DEPDIR)/event.Po
|
||||
-rm -f ./$(DEPDIR)/fake-getaddrinfo.Po
|
||||
-rm -f ./$(DEPDIR)/fake-getnameinfo.Po
|
||||
-rm -f ./$(DEPDIR)/getopt.Po
|
||||
-rm -f ./$(DEPDIR)/getopt1.Po
|
||||
-rm -f ./$(DEPDIR)/graph.Po
|
||||
-rm -f ./$(DEPDIR)/list.Po
|
||||
-rm -f ./$(DEPDIR)/logger.Po
|
||||
-rm -f ./$(DEPDIR)/meta.Po
|
||||
-rm -f ./$(DEPDIR)/multicast_device.Po
|
||||
-rm -f ./$(DEPDIR)/net.Po
|
||||
-rm -f ./$(DEPDIR)/net_packet.Po
|
||||
-rm -f ./$(DEPDIR)/net_setup.Po
|
||||
-rm -f ./$(DEPDIR)/net_socket.Po
|
||||
-rm -f ./$(DEPDIR)/netutl.Po
|
||||
-rm -f ./$(DEPDIR)/node.Po
|
||||
-rm -f ./$(DEPDIR)/pidfile.Po
|
||||
-rm -f ./$(DEPDIR)/process.Po
|
||||
-rm -f ./$(DEPDIR)/protocol.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_auth.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_edge.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_key.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_misc.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_subnet.Po
|
||||
-rm -f ./$(DEPDIR)/proxy.Po
|
||||
-rm -f ./$(DEPDIR)/raw_socket_device.Po
|
||||
-rm -f ./$(DEPDIR)/route.Po
|
||||
-rm -f ./$(DEPDIR)/subnet.Po
|
||||
-rm -f ./$(DEPDIR)/tincd.Po
|
||||
-rm -f ./$(DEPDIR)/uml_device.Po
|
||||
-rm -f ./$(DEPDIR)/utils.Po
|
||||
-rm -f ./$(DEPDIR)/vde_device.Po
|
||||
-rm -f bsd/$(DEPDIR)/device.Po
|
||||
-rm -f bsd/$(DEPDIR)/tunemu.Po
|
||||
-rm -f cygwin/$(DEPDIR)/device.Po
|
||||
-rm -f linux/$(DEPDIR)/device.Po
|
||||
-rm -f mingw/$(DEPDIR)/device.Po
|
||||
-rm -f solaris/$(DEPDIR)/device.Po
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am: install-sbinPROGRAMS
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am: installcheck-sbinPROGRAMS
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f ./$(DEPDIR)/avl_tree.Po
|
||||
-rm -f ./$(DEPDIR)/conf.Po
|
||||
-rm -f ./$(DEPDIR)/connection.Po
|
||||
-rm -f ./$(DEPDIR)/dropin.Po
|
||||
-rm -f ./$(DEPDIR)/dummy_device.Po
|
||||
-rm -f ./$(DEPDIR)/edge.Po
|
||||
-rm -f ./$(DEPDIR)/event.Po
|
||||
-rm -f ./$(DEPDIR)/fake-getaddrinfo.Po
|
||||
-rm -f ./$(DEPDIR)/fake-getnameinfo.Po
|
||||
-rm -f ./$(DEPDIR)/getopt.Po
|
||||
-rm -f ./$(DEPDIR)/getopt1.Po
|
||||
-rm -f ./$(DEPDIR)/graph.Po
|
||||
-rm -f ./$(DEPDIR)/list.Po
|
||||
-rm -f ./$(DEPDIR)/logger.Po
|
||||
-rm -f ./$(DEPDIR)/meta.Po
|
||||
-rm -f ./$(DEPDIR)/multicast_device.Po
|
||||
-rm -f ./$(DEPDIR)/net.Po
|
||||
-rm -f ./$(DEPDIR)/net_packet.Po
|
||||
-rm -f ./$(DEPDIR)/net_setup.Po
|
||||
-rm -f ./$(DEPDIR)/net_socket.Po
|
||||
-rm -f ./$(DEPDIR)/netutl.Po
|
||||
-rm -f ./$(DEPDIR)/node.Po
|
||||
-rm -f ./$(DEPDIR)/pidfile.Po
|
||||
-rm -f ./$(DEPDIR)/process.Po
|
||||
-rm -f ./$(DEPDIR)/protocol.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_auth.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_edge.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_key.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_misc.Po
|
||||
-rm -f ./$(DEPDIR)/protocol_subnet.Po
|
||||
-rm -f ./$(DEPDIR)/proxy.Po
|
||||
-rm -f ./$(DEPDIR)/raw_socket_device.Po
|
||||
-rm -f ./$(DEPDIR)/route.Po
|
||||
-rm -f ./$(DEPDIR)/subnet.Po
|
||||
-rm -f ./$(DEPDIR)/tincd.Po
|
||||
-rm -f ./$(DEPDIR)/uml_device.Po
|
||||
-rm -f ./$(DEPDIR)/utils.Po
|
||||
-rm -f ./$(DEPDIR)/vde_device.Po
|
||||
-rm -f bsd/$(DEPDIR)/device.Po
|
||||
-rm -f bsd/$(DEPDIR)/tunemu.Po
|
||||
-rm -f cygwin/$(DEPDIR)/device.Po
|
||||
-rm -f linux/$(DEPDIR)/device.Po
|
||||
-rm -f mingw/$(DEPDIR)/device.Po
|
||||
-rm -f solaris/$(DEPDIR)/device.Po
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-sbinPROGRAMS
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
|
||||
clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \
|
||||
distclean distclean-compile distclean-generic distclean-tags \
|
||||
distdir dvi dvi-am html html-am info info-am install \
|
||||
install-am install-data install-data-am install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-info install-info-am install-man \
|
||||
install-pdf install-pdf-am install-ps install-ps-am \
|
||||
install-sbinPROGRAMS install-strip installcheck \
|
||||
installcheck-am installcheck-sbinPROGRAMS installdirs \
|
||||
maintainer-clean maintainer-clean-generic mostlyclean \
|
||||
mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
|
||||
# Tell GNU make to disable its built-in pattern rules.
|
||||
%:: %,v
|
||||
%:: RCS/%,v
|
||||
%:: RCS/%
|
||||
%:: s.%
|
||||
%:: SCCS/s.%
|
||||
757
src/avl_tree.c
Normal file
757
src/avl_tree.c
Normal file
|
|
@ -0,0 +1,757 @@
|
|||
/*
|
||||
avl_tree.c -- avl_ tree and linked list convenience
|
||||
Copyright (C) 1998 Michael H. Buselli
|
||||
2000-2005 Ivo Timmermans,
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2005 Wessel Dankers <wsl@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
|
||||
Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
|
||||
|
||||
Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
|
||||
instead of depths, to add the ->next and ->prev and to generally obfuscate
|
||||
the code. Mail me if you found a bug.
|
||||
|
||||
Cleaned up and incorporated some of the ideas from the red-black tree
|
||||
library for inclusion into tinc (https://www.tinc-vpn.org/) by
|
||||
Guus Sliepen <guus@tinc-vpn.org>.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
#define AVL_NODE_COUNT(n) ((n) ? (n)->count : 0)
|
||||
#define AVL_L_COUNT(n) (AVL_NODE_COUNT((n)->left))
|
||||
#define AVL_R_COUNT(n) (AVL_NODE_COUNT((n)->right))
|
||||
#define AVL_CALC_COUNT(n) (AVL_L_COUNT(n) + AVL_R_COUNT(n) + 1)
|
||||
#endif
|
||||
|
||||
#ifdef AVL_DEPTH
|
||||
#define AVL_NODE_DEPTH(n) ((n) ? (n)->depth : 0)
|
||||
#define L_AVL_DEPTH(n) (AVL_NODE_DEPTH((n)->left))
|
||||
#define R_AVL_DEPTH(n) (AVL_NODE_DEPTH((n)->right))
|
||||
#define AVL_CALC_DEPTH(n) ((L_AVL_DEPTH(n)>R_AVL_DEPTH(n)?L_AVL_DEPTH(n):R_AVL_DEPTH(n)) + 1)
|
||||
#endif
|
||||
|
||||
#ifndef AVL_DEPTH
|
||||
static int lg(unsigned int u) __attribute__((__const__));
|
||||
|
||||
static int lg(unsigned int u) {
|
||||
int r = 1;
|
||||
|
||||
if(!u) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(u & 0xffff0000) {
|
||||
u >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
|
||||
if(u & 0x0000ff00) {
|
||||
u >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
|
||||
if(u & 0x000000f0) {
|
||||
u >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
|
||||
if(u & 0x0000000c) {
|
||||
u >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
|
||||
if(u & 0x00000002) {
|
||||
r++;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Internal helper functions */
|
||||
|
||||
static int avl_check_balance(const avl_node_t *node) {
|
||||
#ifdef AVL_DEPTH
|
||||
int d;
|
||||
|
||||
d = R_AVL_DEPTH(node) - L_AVL_DEPTH(node);
|
||||
|
||||
return d < -1 ? -1 : d > 1 ? 1 : 0;
|
||||
#else
|
||||
/* int d;
|
||||
* d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node));
|
||||
* d = d<-1?-1:d>1?1:0;
|
||||
*/
|
||||
int pl, r;
|
||||
|
||||
pl = lg(AVL_L_COUNT(node));
|
||||
r = AVL_R_COUNT(node);
|
||||
|
||||
if(r >> pl + 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(pl < 2 || r >> pl - 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) {
|
||||
avl_node_t *child;
|
||||
avl_node_t *gchild;
|
||||
avl_node_t *parent;
|
||||
avl_node_t **superparent;
|
||||
|
||||
while(node) {
|
||||
parent = node->parent;
|
||||
|
||||
superparent =
|
||||
parent ? node ==
|
||||
parent->left ? &parent->left : &parent->right : &tree->root;
|
||||
|
||||
switch(avl_check_balance(node)) {
|
||||
case -1:
|
||||
child = node->left;
|
||||
#ifdef AVL_DEPTH
|
||||
|
||||
if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) {
|
||||
#else
|
||||
|
||||
if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) {
|
||||
#endif
|
||||
node->left = child->right;
|
||||
|
||||
if(node->left) {
|
||||
node->left->parent = node;
|
||||
}
|
||||
|
||||
child->right = node;
|
||||
node->parent = child;
|
||||
*superparent = child;
|
||||
child->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
child->count = AVL_CALC_COUNT(child);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
child->depth = AVL_CALC_DEPTH(child);
|
||||
#endif
|
||||
} else {
|
||||
gchild = child->right;
|
||||
node->left = gchild->right;
|
||||
|
||||
if(node->left) {
|
||||
node->left->parent = node;
|
||||
}
|
||||
|
||||
child->right = gchild->left;
|
||||
|
||||
if(child->right) {
|
||||
child->right->parent = child;
|
||||
}
|
||||
|
||||
gchild->right = node;
|
||||
|
||||
gchild->right->parent = gchild;
|
||||
gchild->left = child;
|
||||
|
||||
gchild->left->parent = gchild;
|
||||
|
||||
*superparent = gchild;
|
||||
gchild->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
child->count = AVL_CALC_COUNT(child);
|
||||
gchild->count = AVL_CALC_COUNT(gchild);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
child->depth = AVL_CALC_DEPTH(child);
|
||||
gchild->depth = AVL_CALC_DEPTH(gchild);
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
child = node->right;
|
||||
#ifdef AVL_DEPTH
|
||||
|
||||
if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) {
|
||||
#else
|
||||
|
||||
if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) {
|
||||
#endif
|
||||
node->right = child->left;
|
||||
|
||||
if(node->right) {
|
||||
node->right->parent = node;
|
||||
}
|
||||
|
||||
child->left = node;
|
||||
node->parent = child;
|
||||
*superparent = child;
|
||||
child->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
child->count = AVL_CALC_COUNT(child);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
child->depth = AVL_CALC_DEPTH(child);
|
||||
#endif
|
||||
} else {
|
||||
gchild = child->left;
|
||||
node->right = gchild->left;
|
||||
|
||||
if(node->right) {
|
||||
node->right->parent = node;
|
||||
}
|
||||
|
||||
child->left = gchild->right;
|
||||
|
||||
if(child->left) {
|
||||
child->left->parent = child;
|
||||
}
|
||||
|
||||
gchild->left = node;
|
||||
|
||||
gchild->left->parent = gchild;
|
||||
gchild->right = child;
|
||||
|
||||
gchild->right->parent = gchild;
|
||||
|
||||
*superparent = gchild;
|
||||
gchild->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
child->count = AVL_CALC_COUNT(child);
|
||||
gchild->count = AVL_CALC_COUNT(gchild);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
child->depth = AVL_CALC_DEPTH(child);
|
||||
gchild->depth = AVL_CALC_DEPTH(gchild);
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
#endif
|
||||
}
|
||||
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) {
|
||||
avl_tree_t *tree;
|
||||
|
||||
tree = xmalloc_and_zero(sizeof(avl_tree_t));
|
||||
tree->compare = compare;
|
||||
tree->delete = delete;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void avl_free_tree(avl_tree_t *tree) {
|
||||
free(tree);
|
||||
}
|
||||
|
||||
avl_node_t *avl_alloc_node(void) {
|
||||
return xmalloc_and_zero(sizeof(avl_node_t));
|
||||
}
|
||||
|
||||
void avl_free_node(avl_tree_t *tree, avl_node_t *node) {
|
||||
if(node->data && tree->delete) {
|
||||
tree->delete(node->data);
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
/* Searching */
|
||||
|
||||
void *avl_search(const avl_tree_t *tree, const void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_node(tree, data);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_closest_node(tree, data, result);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_closest_smaller_node(tree, data);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_closest_greater_node(tree, data);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) {
|
||||
avl_node_t *node;
|
||||
int result;
|
||||
|
||||
node = avl_search_closest_node(tree, data, &result);
|
||||
|
||||
return result ? NULL : node;
|
||||
}
|
||||
|
||||
avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
|
||||
int *result) {
|
||||
avl_node_t *node;
|
||||
int c;
|
||||
|
||||
node = tree->root;
|
||||
|
||||
if(!node) {
|
||||
if(result) {
|
||||
*result = 0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
c = tree->compare(data, node->data);
|
||||
|
||||
if(c < 0) {
|
||||
if(node->left) {
|
||||
node = node->left;
|
||||
} else {
|
||||
if(result) {
|
||||
*result = -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} else if(c > 0) {
|
||||
if(node->right) {
|
||||
node = node->right;
|
||||
} else {
|
||||
if(result) {
|
||||
*result = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(result) {
|
||||
*result = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree,
|
||||
const void *data) {
|
||||
avl_node_t *node;
|
||||
int result;
|
||||
|
||||
node = avl_search_closest_node(tree, data, &result);
|
||||
|
||||
if(result < 0) {
|
||||
node = node->prev;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree,
|
||||
const void *data) {
|
||||
avl_node_t *node;
|
||||
int result;
|
||||
|
||||
node = avl_search_closest_node(tree, data, &result);
|
||||
|
||||
if(result > 0) {
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
avl_node_t *avl_insert(avl_tree_t *tree, void *data) {
|
||||
avl_node_t *closest, *new;
|
||||
int result;
|
||||
|
||||
if(!tree->root) {
|
||||
new = avl_alloc_node();
|
||||
new->data = data;
|
||||
avl_insert_top(tree, new);
|
||||
} else {
|
||||
closest = avl_search_closest_node(tree, data, &result);
|
||||
|
||||
switch(result) {
|
||||
case -1:
|
||||
new = avl_alloc_node();
|
||||
new->data = data;
|
||||
avl_insert_before(tree, closest, new);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
new = avl_alloc_node();
|
||||
new->data = data;
|
||||
avl_insert_after(tree, closest, new);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
new->count = 1;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
new->depth = 1;
|
||||
#endif
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) {
|
||||
avl_node_t *closest;
|
||||
int result;
|
||||
|
||||
if(!tree->root) {
|
||||
avl_insert_top(tree, node);
|
||||
} else {
|
||||
closest = avl_search_closest_node(tree, node->data, &result);
|
||||
|
||||
switch(result) {
|
||||
case -1:
|
||||
avl_insert_before(tree, closest, node);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
avl_insert_after(tree, closest, node);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
node->count = 1;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = 1;
|
||||
#endif
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void avl_insert_top(avl_tree_t *tree, avl_node_t *node) {
|
||||
node->prev = node->next = node->parent = NULL;
|
||||
tree->head = tree->tail = tree->root = node;
|
||||
}
|
||||
|
||||
void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
|
||||
avl_node_t *node) {
|
||||
if(!before) {
|
||||
if(tree->tail) {
|
||||
avl_insert_after(tree, tree->tail, node);
|
||||
} else {
|
||||
avl_insert_top(tree, node);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
node->next = before;
|
||||
node->parent = before;
|
||||
node->prev = before->prev;
|
||||
|
||||
if(before->left) {
|
||||
avl_insert_after(tree, before->prev, node);
|
||||
return;
|
||||
}
|
||||
|
||||
if(before->prev) {
|
||||
before->prev->next = node;
|
||||
} else {
|
||||
tree->head = node;
|
||||
}
|
||||
|
||||
before->prev = node;
|
||||
before->left = node;
|
||||
|
||||
avl_rebalance(tree, before);
|
||||
}
|
||||
|
||||
void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) {
|
||||
if(!after) {
|
||||
if(tree->head) {
|
||||
avl_insert_before(tree, tree->head, node);
|
||||
} else {
|
||||
avl_insert_top(tree, node);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(after->right) {
|
||||
avl_insert_before(tree, after->next, node);
|
||||
return;
|
||||
}
|
||||
|
||||
node->prev = after;
|
||||
node->parent = after;
|
||||
node->next = after->next;
|
||||
|
||||
if(after->next) {
|
||||
after->next->prev = node;
|
||||
} else {
|
||||
tree->tail = node;
|
||||
}
|
||||
|
||||
after->next = node;
|
||||
after->right = node;
|
||||
|
||||
avl_rebalance(tree, after);
|
||||
}
|
||||
|
||||
avl_node_t *avl_unlink(avl_tree_t *tree, void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_node(tree, data);
|
||||
|
||||
if(node) {
|
||||
avl_unlink_node(tree, node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) {
|
||||
avl_node_t *parent;
|
||||
avl_node_t **superparent;
|
||||
avl_node_t *subst, *left, *right;
|
||||
avl_node_t *balnode;
|
||||
|
||||
if(node->prev) {
|
||||
node->prev->next = node->next;
|
||||
} else {
|
||||
tree->head = node->next;
|
||||
}
|
||||
|
||||
if(node->next) {
|
||||
node->next->prev = node->prev;
|
||||
} else {
|
||||
tree->tail = node->prev;
|
||||
}
|
||||
|
||||
parent = node->parent;
|
||||
|
||||
superparent =
|
||||
parent ? node ==
|
||||
parent->left ? &parent->left : &parent->right : &tree->root;
|
||||
|
||||
left = node->left;
|
||||
right = node->right;
|
||||
|
||||
if(!left) {
|
||||
*superparent = right;
|
||||
|
||||
if(right) {
|
||||
right->parent = parent;
|
||||
}
|
||||
|
||||
balnode = parent;
|
||||
} else if(!right) {
|
||||
*superparent = left;
|
||||
left->parent = parent;
|
||||
balnode = parent;
|
||||
} else {
|
||||
subst = node->prev;
|
||||
|
||||
if(!subst) { // This only happens if node is not actually in a tree at all.
|
||||
abort();
|
||||
}
|
||||
|
||||
if(subst == left) {
|
||||
balnode = subst;
|
||||
} else {
|
||||
balnode = subst->parent;
|
||||
balnode->right = subst->left;
|
||||
|
||||
if(balnode->right) {
|
||||
balnode->right->parent = balnode;
|
||||
}
|
||||
|
||||
subst->left = left;
|
||||
left->parent = subst;
|
||||
}
|
||||
|
||||
subst->right = right;
|
||||
subst->parent = parent;
|
||||
right->parent = subst;
|
||||
*superparent = subst;
|
||||
}
|
||||
|
||||
avl_rebalance(tree, balnode);
|
||||
|
||||
node->next = node->prev = node->parent = node->left = node->right = NULL;
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
node->count = 0;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void avl_delete_node(avl_tree_t *tree, avl_node_t *node) {
|
||||
avl_unlink_node(tree, node);
|
||||
avl_free_node(tree, node);
|
||||
}
|
||||
|
||||
void avl_delete(avl_tree_t *tree, void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_node(tree, data);
|
||||
|
||||
if(node) {
|
||||
avl_delete_node(tree, node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fast tree cleanup */
|
||||
|
||||
void avl_delete_tree(avl_tree_t *tree) {
|
||||
avl_node_t *node, *next;
|
||||
|
||||
for(node = tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
avl_free_node(tree, node);
|
||||
}
|
||||
|
||||
avl_free_tree(tree);
|
||||
}
|
||||
|
||||
/* Tree walking */
|
||||
|
||||
void avl_foreach(const avl_tree_t *tree, avl_action_t action) {
|
||||
avl_node_t *node, *next;
|
||||
|
||||
for(node = tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
action(node->data);
|
||||
}
|
||||
}
|
||||
|
||||
void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) {
|
||||
avl_node_t *node, *next;
|
||||
|
||||
for(node = tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
action(node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Indexing */
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
unsigned int avl_count(const avl_tree_t *tree) {
|
||||
return AVL_NODE_COUNT(tree->root);
|
||||
}
|
||||
|
||||
avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) {
|
||||
avl_node_t *node;
|
||||
unsigned int c;
|
||||
|
||||
node = tree->root;
|
||||
|
||||
while(node) {
|
||||
c = AVL_L_COUNT(node);
|
||||
|
||||
if(index < c) {
|
||||
node = node->left;
|
||||
} else if(index > c) {
|
||||
node = node->right;
|
||||
index -= c + 1;
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int avl_index(const avl_node_t *node) {
|
||||
avl_node_t *next;
|
||||
unsigned int index;
|
||||
|
||||
index = AVL_L_COUNT(node);
|
||||
|
||||
while((next = node->parent)) {
|
||||
if(node == next->right) {
|
||||
index += AVL_L_COUNT(next) + 1;
|
||||
}
|
||||
|
||||
node = next;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
unsigned int avl_depth(const avl_tree_t *tree) {
|
||||
return AVL_NODE_DEPTH(tree->root);
|
||||
}
|
||||
#endif
|
||||
142
src/avl_tree.h
Normal file
142
src/avl_tree.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#ifndef TINC_AVL_TREE_H
|
||||
#define TINC_AVL_TREE_H
|
||||
|
||||
/*
|
||||
avl_tree.h -- header file for avl_tree.c
|
||||
Copyright (C) 1998 Michael H. Buselli
|
||||
2000-2005 Ivo Timmermans,
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2005 Wessel Dankers <wsl@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
|
||||
Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
|
||||
|
||||
Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
|
||||
instead of depths, to add the ->next and ->prev and to generally obfuscate
|
||||
the code. Mail me if you found a bug.
|
||||
|
||||
Cleaned up and incorporated some of the ideas from the red-black tree
|
||||
library for inclusion into tinc (https://www.tinc-vpn.org/) by
|
||||
Guus Sliepen <guus@tinc-vpn.org>.
|
||||
*/
|
||||
|
||||
#ifndef AVL_DEPTH
|
||||
#ifndef AVL_COUNT
|
||||
#define AVL_DEPTH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct avl_node_t {
|
||||
|
||||
/* Linked list part */
|
||||
|
||||
struct avl_node_t *next;
|
||||
struct avl_node_t *prev;
|
||||
|
||||
/* Tree part */
|
||||
|
||||
struct avl_node_t *parent;
|
||||
struct avl_node_t *left;
|
||||
struct avl_node_t *right;
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
unsigned int count;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
unsigned char depth;
|
||||
#endif
|
||||
|
||||
/* Payload */
|
||||
|
||||
void *data;
|
||||
|
||||
} avl_node_t;
|
||||
|
||||
typedef int (*avl_compare_t)(const void *data1, const void *data2);
|
||||
typedef void (*avl_action_t)(const void *data);
|
||||
typedef void (*avl_action_node_t)(const avl_node_t *node);
|
||||
|
||||
typedef struct avl_tree_t {
|
||||
|
||||
/* Linked list part */
|
||||
|
||||
avl_node_t *head;
|
||||
avl_node_t *tail;
|
||||
|
||||
/* Tree part */
|
||||
|
||||
avl_node_t *root;
|
||||
|
||||
avl_compare_t compare;
|
||||
avl_action_t delete;
|
||||
|
||||
} avl_tree_t;
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
extern avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete);
|
||||
extern void avl_free_tree(avl_tree_t *tree);
|
||||
|
||||
extern avl_node_t *avl_alloc_node(void);
|
||||
extern void avl_free_node(avl_tree_t *tree, avl_node_t *node);
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
extern avl_node_t *avl_insert(avl_tree_t *tree, void *data);
|
||||
extern avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node);
|
||||
|
||||
extern void avl_insert_top(avl_tree_t *tree, avl_node_t *node);
|
||||
extern void avl_insert_before(avl_tree_t *tree, avl_node_t *before, avl_node_t *node);
|
||||
extern void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node);
|
||||
|
||||
extern avl_node_t *avl_unlink(avl_tree_t *tree, void *data);
|
||||
extern void avl_unlink_node(avl_tree_t *tree, avl_node_t *node);
|
||||
extern void avl_delete(avl_tree_t *tree, void *data);
|
||||
extern void avl_delete_node(avl_tree_t *tree, avl_node_t *node);
|
||||
|
||||
/* Fast tree cleanup */
|
||||
|
||||
extern void avl_delete_tree(avl_tree_t *tree);
|
||||
|
||||
/* Searching */
|
||||
|
||||
extern void *avl_search(const avl_tree_t *tree, const void *data);
|
||||
extern void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result);
|
||||
extern void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data);
|
||||
extern void *avl_search_closest_greater(const avl_tree_t *tree, const void *data);
|
||||
|
||||
extern avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data);
|
||||
extern avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data, int *result);
|
||||
extern avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree, const void *data);
|
||||
extern avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree, const void *data);
|
||||
|
||||
/* Tree walking */
|
||||
|
||||
extern void avl_foreach(const avl_tree_t *tree, avl_action_t action);
|
||||
extern void avl_foreach_node(const avl_tree_t *tree, avl_action_t action);
|
||||
|
||||
/* Indexing */
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
extern unsigned int avl_count(const avl_tree_t *tree);
|
||||
extern avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index);
|
||||
extern unsigned int avl_index(const avl_node_t *node);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
extern unsigned int avl_depth(const avl_tree_t *tree);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
886
src/bsd/device.c
Normal file
886
src/bsd/device.c
Normal file
|
|
@ -0,0 +1,886 @@
|
|||
/*
|
||||
device.c -- Interaction BSD tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../net.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
#ifdef ENABLE_TUNEMU
|
||||
#include "tunemu.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
#include <sys/sys_domain.h>
|
||||
#include <sys/kern_control.h>
|
||||
#include <net/if_utun.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DARWIN
|
||||
#include <net/bpf.h>
|
||||
#include <net/ndrv.h>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_TUN_DEVICE "/dev/tun0"
|
||||
#define DEFAULT_TAP_DEVICE "/dev/tap0"
|
||||
|
||||
typedef enum device_type {
|
||||
DEVICE_TYPE_TUN,
|
||||
DEVICE_TYPE_TUNIFHEAD,
|
||||
DEVICE_TYPE_TAP,
|
||||
#ifdef ENABLE_TUNEMU
|
||||
DEVICE_TYPE_TUNEMU,
|
||||
#endif
|
||||
DEVICE_TYPE_UTUN,
|
||||
#ifdef HAVE_DARWIN
|
||||
DEVICE_TYPE_FETH,
|
||||
#endif
|
||||
} device_type_t;
|
||||
|
||||
int device_fd = -1;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static const char *device_info = "OS X utun device";
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
#if defined(ENABLE_TUNEMU)
|
||||
static device_type_t device_type = DEVICE_TYPE_TUNEMU;
|
||||
#elif defined(HAVE_OPENBSD) || defined(HAVE_FREEBSD) || defined(HAVE_DRAGONFLY)
|
||||
static device_type_t device_type = DEVICE_TYPE_TUNIFHEAD;
|
||||
#else
|
||||
static device_type_t device_type = DEVICE_TYPE_TUN;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DARWIN
|
||||
/* feth (fake ethernet) device support for macOS 10.13+
|
||||
*
|
||||
* Uses undocumented feth interfaces (like Linux veth pairs) to provide
|
||||
* Layer 2 / TAP functionality without kernel extensions.
|
||||
*
|
||||
* Architecture:
|
||||
* feth<N> (primary) - gets IP assignments, used by tinc-up scripts
|
||||
* feth<N+5000> (peer) - used for packet I/O via BPF read + AF_NDRV write
|
||||
*
|
||||
* Based on ZeroTier's MacEthernetTapAgent approach.
|
||||
*/
|
||||
|
||||
#define FETH_BPF_BUFSIZE 131072
|
||||
#define FETH_PEER_OFFSET 5000
|
||||
#define DEFAULT_FETH_NUM 0
|
||||
|
||||
static int feth_ndrv_fd = -1;
|
||||
static int feth_num = -1;
|
||||
static char feth_primary[IFNAMSIZ];
|
||||
static char feth_peer[IFNAMSIZ];
|
||||
static uint8_t feth_bpf_buf[FETH_BPF_BUFSIZE];
|
||||
static int feth_bpf_buf_len = 0;
|
||||
static int feth_bpf_buf_offset = 0;
|
||||
|
||||
static bool feth_run_cmd(const char *cmd) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Executing: %s", cmd);
|
||||
|
||||
int ret = system(cmd);
|
||||
|
||||
if(ret != 0) {
|
||||
logger(LOG_ERR, "Command failed (exit %d): %s", ret, cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool setup_feth(void) {
|
||||
char cmd[512];
|
||||
|
||||
/* Parse device number from Device config (e.g. "feth0" -> 0) */
|
||||
feth_num = DEFAULT_FETH_NUM;
|
||||
|
||||
if(device) {
|
||||
char *p = strstr(device, "feth");
|
||||
|
||||
if(p) {
|
||||
int n = atoi(p + 4);
|
||||
|
||||
if(n >= 0 && n < FETH_PEER_OFFSET) {
|
||||
feth_num = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(feth_primary, sizeof(feth_primary), "feth%d", feth_num);
|
||||
snprintf(feth_peer, sizeof(feth_peer), "feth%d", feth_num + FETH_PEER_OFFSET);
|
||||
|
||||
/* Create feth pair */
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s create", feth_peer);
|
||||
|
||||
if(!feth_run_cmd(cmd)) {
|
||||
logger(LOG_ERR, "Could not create feth peer interface %s", feth_peer);
|
||||
return false;
|
||||
}
|
||||
|
||||
usleep(10000); /* Brief delay for interface to stabilize */
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s create", feth_primary);
|
||||
|
||||
if(!feth_run_cmd(cmd)) {
|
||||
logger(LOG_ERR, "Could not create feth primary interface %s", feth_primary);
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s destroy 2>/dev/null", feth_peer);
|
||||
feth_run_cmd(cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Peer the interfaces */
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s peer %s", feth_peer, feth_primary);
|
||||
|
||||
if(!feth_run_cmd(cmd)) {
|
||||
logger(LOG_ERR, "Could not peer %s with %s", feth_peer, feth_primary);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Set MTU */
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s mtu 1500", feth_primary);
|
||||
feth_run_cmd(cmd);
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s mtu 1500", feth_peer);
|
||||
feth_run_cmd(cmd);
|
||||
|
||||
/* Bring interfaces up */
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s up", feth_primary);
|
||||
|
||||
if(!feth_run_cmd(cmd)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s up", feth_peer);
|
||||
|
||||
if(!feth_run_cmd(cmd)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Open BPF device */
|
||||
char bpf_path[32];
|
||||
|
||||
for(int i = 1; i < 5000; i++) {
|
||||
snprintf(bpf_path, sizeof(bpf_path), "/dev/bpf%d", i);
|
||||
device_fd = open(bpf_path, O_RDWR);
|
||||
|
||||
if(device_fd >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(LOG_ERR, "Could not open any BPF device: %s", strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
/* Configure BPF - order matters: BIOCSBLEN must come before BIOCSETIF */
|
||||
int bpf_bufsize = FETH_BPF_BUFSIZE;
|
||||
|
||||
if(ioctl(device_fd, BIOCSBLEN, &bpf_bufsize) == -1) {
|
||||
logger(LOG_ERR, "Could not set BPF buffer size: %s", strerror(errno));
|
||||
goto cleanup_bpf;
|
||||
}
|
||||
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strlcpy(ifr.ifr_name, feth_peer, sizeof(ifr.ifr_name));
|
||||
|
||||
if(ioctl(device_fd, BIOCSETIF, &ifr) == -1) {
|
||||
logger(LOG_ERR, "Could not bind BPF to %s: %s", feth_peer, strerror(errno));
|
||||
goto cleanup_bpf;
|
||||
}
|
||||
|
||||
int enable = 1;
|
||||
|
||||
if(ioctl(device_fd, BIOCIMMEDIATE, &enable) == -1) {
|
||||
logger(LOG_ERR, "Could not set BIOCIMMEDIATE: %s", strerror(errno));
|
||||
goto cleanup_bpf;
|
||||
}
|
||||
|
||||
int disable = 0;
|
||||
|
||||
if(ioctl(device_fd, BIOCSSEESENT, &disable) == -1) {
|
||||
logger(LOG_ERR, "Could not set BIOCSSEESENT: %s", strerror(errno));
|
||||
goto cleanup_bpf;
|
||||
}
|
||||
|
||||
if(ioctl(device_fd, BIOCSHDRCMPLT, &enable) == -1) {
|
||||
logger(LOG_ERR, "Could not set BIOCSHDRCMPLT: %s", strerror(errno));
|
||||
goto cleanup_bpf;
|
||||
}
|
||||
|
||||
if(ioctl(device_fd, BIOCPROMISC, NULL) == -1) {
|
||||
logger(LOG_ERR, "Could not set BPF promiscuous mode: %s", strerror(errno));
|
||||
goto cleanup_bpf;
|
||||
}
|
||||
|
||||
/* Set non-blocking mode for integration with tinc's event loop */
|
||||
fcntl(device_fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
/* Open AF_NDRV socket for writing packets */
|
||||
feth_ndrv_fd = socket(PF_NDRV, SOCK_RAW, 0);
|
||||
|
||||
if(feth_ndrv_fd < 0) {
|
||||
logger(LOG_ERR, "Could not create AF_NDRV socket: %s", strerror(errno));
|
||||
goto cleanup_bpf;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(feth_ndrv_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
struct sockaddr_ndrv sa_ndrv;
|
||||
memset(&sa_ndrv, 0, sizeof(sa_ndrv));
|
||||
sa_ndrv.snd_len = sizeof(sa_ndrv);
|
||||
sa_ndrv.snd_family = AF_NDRV;
|
||||
strlcpy((char *)sa_ndrv.snd_name, feth_peer, sizeof(sa_ndrv.snd_name));
|
||||
|
||||
if(bind(feth_ndrv_fd, (struct sockaddr *)&sa_ndrv, sizeof(sa_ndrv)) == -1) {
|
||||
logger(LOG_ERR, "Could not bind AF_NDRV socket to %s: %s", feth_peer, strerror(errno));
|
||||
goto cleanup_ndrv;
|
||||
}
|
||||
|
||||
if(connect(feth_ndrv_fd, (struct sockaddr *)&sa_ndrv, sizeof(sa_ndrv)) == -1) {
|
||||
logger(LOG_ERR, "Could not connect AF_NDRV socket to %s: %s", feth_peer, strerror(errno));
|
||||
goto cleanup_ndrv;
|
||||
}
|
||||
|
||||
/* Set interface name for tinc-up scripts */
|
||||
iface = xstrdup(feth_primary);
|
||||
device_info = "macOS feth device";
|
||||
|
||||
/* Initialize BPF read buffer state */
|
||||
feth_bpf_buf_len = 0;
|
||||
feth_bpf_buf_offset = 0;
|
||||
|
||||
logger(LOG_INFO, "%s is a %s (peer: %s, bpf: %s)", feth_primary, device_info, feth_peer, bpf_path);
|
||||
|
||||
return true;
|
||||
|
||||
cleanup_ndrv:
|
||||
close(feth_ndrv_fd);
|
||||
feth_ndrv_fd = -1;
|
||||
cleanup_bpf:
|
||||
close(device_fd);
|
||||
device_fd = -1;
|
||||
cleanup:
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s destroy 2>/dev/null", feth_primary);
|
||||
feth_run_cmd(cmd);
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s destroy 2>/dev/null", feth_peer);
|
||||
feth_run_cmd(cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void close_feth(void) {
|
||||
char cmd[256];
|
||||
|
||||
if(feth_ndrv_fd >= 0) {
|
||||
close(feth_ndrv_fd);
|
||||
feth_ndrv_fd = -1;
|
||||
}
|
||||
|
||||
if(device_fd >= 0) {
|
||||
close(device_fd);
|
||||
device_fd = -1;
|
||||
}
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s destroy 2>/dev/null", feth_primary);
|
||||
feth_run_cmd(cmd);
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/ifconfig %s destroy 2>/dev/null", feth_peer);
|
||||
feth_run_cmd(cmd);
|
||||
|
||||
logger(LOG_INFO, "Destroyed feth pair %s/%s", feth_primary, feth_peer);
|
||||
}
|
||||
|
||||
static bool read_feth_packet(vpn_packet_t *packet) {
|
||||
/* BPF returns multiple packets per read() in a buffer with bpf_hdr prefixes.
|
||||
* We maintain a static buffer and return one packet per call. */
|
||||
|
||||
if(feth_bpf_buf_offset >= feth_bpf_buf_len) {
|
||||
/* Buffer exhausted, read more from BPF */
|
||||
feth_bpf_buf_len = read(device_fd, feth_bpf_buf, FETH_BPF_BUFSIZE);
|
||||
|
||||
if(feth_bpf_buf_len <= 0) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
logger(LOG_ERR, "Error reading from BPF: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
feth_bpf_buf_offset = 0;
|
||||
}
|
||||
|
||||
/* Parse next packet from buffer */
|
||||
struct bpf_hdr *bh = (struct bpf_hdr *)(feth_bpf_buf + feth_bpf_buf_offset);
|
||||
uint8_t *frame = feth_bpf_buf + feth_bpf_buf_offset + bh->bh_hdrlen;
|
||||
int caplen = bh->bh_caplen;
|
||||
|
||||
/* Advance offset to next packet (word-aligned) */
|
||||
feth_bpf_buf_offset += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
|
||||
|
||||
if(caplen <= 0 || caplen > MTU) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Dropping oversized feth packet (%d bytes)", caplen);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(packet->data, frame, caplen);
|
||||
packet->len = caplen;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_feth_packet(vpn_packet_t *packet) {
|
||||
if(write(feth_ndrv_fd, packet->data, packet->len) < 0) {
|
||||
logger(LOG_ERR, "Error writing to feth AF_NDRV: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif /* HAVE_DARWIN */
|
||||
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
static bool setup_utun(void) {
|
||||
device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||
|
||||
if(device_fd == -1) {
|
||||
logger(LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ctl_info info = {};
|
||||
|
||||
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name));
|
||||
|
||||
if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) {
|
||||
logger(LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
int unit = -1;
|
||||
char *p = strstr(device, "utun"), *e = NULL;
|
||||
|
||||
if(p) {
|
||||
unit = strtol(p + 4, &e, 10);
|
||||
|
||||
if(!e) {
|
||||
unit = -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_ctl sc = {
|
||||
.sc_id = info.ctl_id,
|
||||
.sc_len = sizeof(sc),
|
||||
.sc_family = AF_SYSTEM,
|
||||
.ss_sysaddr = AF_SYS_CONTROL,
|
||||
.sc_unit = unit + 1,
|
||||
};
|
||||
|
||||
if(connect(device_fd, (struct sockaddr *)&sc, sizeof(sc)) == -1) {
|
||||
logger(LOG_ERR, "Could not connect utun socket: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
char name[64] = "";
|
||||
socklen_t len = sizeof(name);
|
||||
|
||||
if(getsockopt(device_fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &len)) {
|
||||
iface = xstrdup(device);
|
||||
} else {
|
||||
iface = xstrdup(name);
|
||||
}
|
||||
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool setup_device(void) {
|
||||
// Find out which device file to open
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
if(routing_mode == RMODE_ROUTER) {
|
||||
device = xstrdup(DEFAULT_TUN_DEVICE);
|
||||
} else {
|
||||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
// Find out if it's supposed to be a tun or a tap device
|
||||
|
||||
char *type;
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
|
||||
if(!strcasecmp(type, "tun"))
|
||||
/* use default */;
|
||||
|
||||
#ifdef ENABLE_TUNEMU
|
||||
else if(!strcasecmp(type, "tunemu")) {
|
||||
device_type = DEVICE_TYPE_TUNEMU;
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
else if(!strcasecmp(type, "utun")) {
|
||||
device_type = DEVICE_TYPE_UTUN;
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef HAVE_DARWIN
|
||||
else if(!strcasecmp(type, "feth")) {
|
||||
device_type = DEVICE_TYPE_FETH;
|
||||
}
|
||||
|
||||
#endif
|
||||
else if(!strcasecmp(type, "tunnohead")) {
|
||||
device_type = DEVICE_TYPE_TUN;
|
||||
} else if(!strcasecmp(type, "tunifhead")) {
|
||||
device_type = DEVICE_TYPE_TUNIFHEAD;
|
||||
} else if(!strcasecmp(type, "tap")) {
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
} else {
|
||||
logger(LOG_ERR, "Unknown device type %s!", type);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
|
||||
if(strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0) {
|
||||
device_type = DEVICE_TYPE_UTUN;
|
||||
} else
|
||||
#endif
|
||||
#ifdef HAVE_DARWIN
|
||||
|
||||
if(strncmp(device, "feth", 4) == 0) {
|
||||
device_type = DEVICE_TYPE_FETH;
|
||||
} else
|
||||
#endif
|
||||
if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) {
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DARWIN
|
||||
|
||||
if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP && device_type != DEVICE_TYPE_FETH) {
|
||||
logger(LOG_ERR, "Only tap or feth devices support switch mode!");
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) {
|
||||
logger(LOG_ERR, "Only tap devices support switch mode!");
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Open the device
|
||||
|
||||
switch(device_type) {
|
||||
#ifdef ENABLE_TUNEMU
|
||||
|
||||
case DEVICE_TYPE_TUNEMU: {
|
||||
char dynamic_name[256] = "";
|
||||
device_fd = tunemu_open(dynamic_name);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
|
||||
case DEVICE_TYPE_UTUN:
|
||||
return setup_utun();
|
||||
#endif
|
||||
#ifdef HAVE_DARWIN
|
||||
|
||||
case DEVICE_TYPE_FETH:
|
||||
return setup_feth();
|
||||
#endif
|
||||
|
||||
default:
|
||||
device_fd = open(device, O_RDWR | O_NONBLOCK);
|
||||
}
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
// Guess what the corresponding interface is called
|
||||
|
||||
char *realname = NULL;
|
||||
|
||||
#if defined(HAVE_FDEVNAME)
|
||||
realname = fdevname(device_fd);
|
||||
#elif defined(HAVE_DEVNAME)
|
||||
struct stat buf;
|
||||
|
||||
if(!fstat(device_fd, &buf)) {
|
||||
realname = devname(buf.st_rdev, S_IFCHR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(!realname) {
|
||||
realname = device;
|
||||
}
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) {
|
||||
iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname);
|
||||
} else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname)) {
|
||||
logger(LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
|
||||
}
|
||||
|
||||
// Configure the device as best as we can
|
||||
|
||||
switch(device_type) {
|
||||
default:
|
||||
device_type = DEVICE_TYPE_TUN;
|
||||
|
||||
case DEVICE_TYPE_TUN:
|
||||
#ifdef TUNSIFHEAD
|
||||
{
|
||||
const int zero = 0;
|
||||
|
||||
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof(zero)) == -1) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST)
|
||||
{
|
||||
const int mode = IFF_BROADCAST | IFF_MULTICAST;
|
||||
ioctl(device_fd, TUNSIFMODE, &mode, sizeof(mode));
|
||||
}
|
||||
#endif
|
||||
|
||||
device_info = "Generic BSD tun device";
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_TUNIFHEAD:
|
||||
#ifdef TUNSIFHEAD
|
||||
{
|
||||
const int one = 1;
|
||||
|
||||
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof(one)) == -1) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#if defined(TUNSIFMODE) && defined(IFF_BROADCAST) && defined(IFF_MULTICAST)
|
||||
{
|
||||
const int mode = IFF_BROADCAST | IFF_MULTICAST;
|
||||
ioctl(device_fd, TUNSIFMODE, &mode, sizeof(mode));
|
||||
}
|
||||
#endif
|
||||
|
||||
device_info = "Generic BSD tun device";
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(routing_mode == RMODE_ROUTER) {
|
||||
overwrite_mac = true;
|
||||
}
|
||||
|
||||
device_info = "Generic BSD tap device";
|
||||
#ifdef TAPGIFNAME
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
if(ioctl(device_fd, TAPGIFNAME, (void *)&ifr) == 0) {
|
||||
if(iface) {
|
||||
free(iface);
|
||||
}
|
||||
|
||||
iface = xstrdup(ifr.ifr_name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
break;
|
||||
#ifdef ENABLE_TUNEMU
|
||||
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
device_info = "BSD tunemu device";
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SIOCGIFADDR
|
||||
|
||||
if(overwrite_mac) {
|
||||
ioctl(device_fd, SIOCGIFADDR, mymac.x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
switch(device_type) {
|
||||
#ifdef ENABLE_TUNEMU
|
||||
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
tunemu_close(device_fd);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_DARWIN
|
||||
|
||||
case DEVICE_TYPE_FETH:
|
||||
close_feth();
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
close(device_fd);
|
||||
}
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin;
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
#ifdef ENABLE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
if(device_type == DEVICE_TYPE_TUNEMU) {
|
||||
lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14);
|
||||
} else
|
||||
#endif
|
||||
lenin = read(device_fd, packet->data + 14, MTU - 14);
|
||||
|
||||
if(lenin <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(packet->data[14] >> 4) {
|
||||
case 4:
|
||||
packet->data[12] = 0x08;
|
||||
packet->data[13] = 0x00;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
packet->data[12] = 0x86;
|
||||
packet->data[13] = 0xDD;
|
||||
break;
|
||||
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = lenin + 14;
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_UTUN:
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
if((lenin = read(device_fd, packet->data + 10, MTU - 10)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(packet->data[14] >> 4) {
|
||||
case 4:
|
||||
packet->data[12] = 0x08;
|
||||
packet->data[13] = 0x00;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
packet->data[12] = 0x86;
|
||||
packet->data[13] = 0xDD;
|
||||
break;
|
||||
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = lenin + 10;
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->len = lenin;
|
||||
break;
|
||||
|
||||
#ifdef HAVE_DARWIN
|
||||
|
||||
case DEVICE_TYPE_FETH:
|
||||
if(!read_feth_packet(packet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
|
||||
packet->len, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_UTUN:
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
int af = (packet->data[12] << 8) + packet->data[13];
|
||||
uint32_t type;
|
||||
|
||||
switch(af) {
|
||||
case 0x0800:
|
||||
type = htonl(AF_INET);
|
||||
break;
|
||||
|
||||
case 0x86DD:
|
||||
type = htonl(AF_INET6);
|
||||
break;
|
||||
|
||||
default:
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
"Unknown address family %x while writing packet to %s %s",
|
||||
af, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(packet->data + 10, &type, sizeof(type));
|
||||
|
||||
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_TUNEMU
|
||||
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DARWIN
|
||||
|
||||
case DEVICE_TYPE_FETH:
|
||||
if(!write_feth_packet(packet)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
377
src/bsd/tunemu.c
Normal file
377
src/bsd/tunemu.c
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
* tunemu - Tun device emulation for Darwin
|
||||
* Copyright (C) 2009 Friedrich Schöller <friedrich.schoeller@gmail.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tunemu.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <util.h>
|
||||
#include <pcap.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define PPPPROTO_CTL 1
|
||||
|
||||
#define PPP_IP 0x21
|
||||
#define PPP_IPV6 0x57
|
||||
|
||||
#define SC_LOOP_TRAFFIC 0x00000200
|
||||
|
||||
#define PPPIOCNEWUNIT _IOWR('t', 62, int)
|
||||
#define PPPIOCSFLAGS _IOW('t', 89, int)
|
||||
#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl)
|
||||
#define PPPIOCATTCHAN _IOW('t', 56, int)
|
||||
#define PPPIOCGCHAN _IOR('t', 55, int)
|
||||
#define PPPIOCCONNECT _IOW('t', 58, int)
|
||||
#define PPPIOCGUNIT _IOR('t', 86, int)
|
||||
|
||||
struct sockaddr_ppp {
|
||||
u_int8_t ppp_len;
|
||||
u_int8_t ppp_family;
|
||||
u_int16_t ppp_proto;
|
||||
u_int32_t ppp_cookie;
|
||||
};
|
||||
|
||||
enum NPmode {
|
||||
NPMODE_PASS,
|
||||
NPMODE_DROP,
|
||||
NPMODE_ERROR,
|
||||
NPMODE_QUEUE
|
||||
};
|
||||
|
||||
struct npioctl {
|
||||
int protocol;
|
||||
enum NPmode mode;
|
||||
};
|
||||
|
||||
#define PPP_KEXT_PATH "/System/Library/Extensions/PPP.kext"
|
||||
|
||||
#define ERROR_BUFFER_SIZE 1024
|
||||
|
||||
char tunemu_error[ERROR_BUFFER_SIZE];
|
||||
|
||||
static int pcap_use_count = 0;
|
||||
static pcap_t *pcap = NULL;
|
||||
|
||||
static int data_buffer_length = 0;
|
||||
static char *data_buffer = NULL;
|
||||
|
||||
static void tun_error(char *format, ...) {
|
||||
va_list vl;
|
||||
va_start(vl, format);
|
||||
vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, format, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
static void tun_noerror() {
|
||||
*tunemu_error = 0;
|
||||
}
|
||||
|
||||
static void closeall() {
|
||||
int fd = getdtablesize();
|
||||
|
||||
while(fd--) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
open("/dev/null", O_RDWR, 0);
|
||||
dup(0);
|
||||
dup(0);
|
||||
}
|
||||
|
||||
static int ppp_load_kext() {
|
||||
int pid = fork();
|
||||
|
||||
if(pid < 0) {
|
||||
tun_error("fork for ppp kext: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pid == 0) {
|
||||
closeall();
|
||||
execle("/sbin/kextload", "kextload", PPP_KEXT_PATH, NULL, NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int status;
|
||||
|
||||
while(waitpid(pid, &status, 0) < 0) {
|
||||
if(errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tun_error("waitpid for ppp kext: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(WEXITSTATUS(status) != 0) {
|
||||
tun_error("could not load ppp kext \"%s\"", PPP_KEXT_PATH);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tun_noerror();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ppp_new_instance() {
|
||||
// create ppp socket
|
||||
int ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL);
|
||||
|
||||
if(ppp_sockfd < 0) {
|
||||
if(ppp_load_kext() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ppp_sockfd = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL);
|
||||
|
||||
if(ppp_sockfd < 0) {
|
||||
tun_error("creating ppp socket: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// connect to ppp protocol
|
||||
struct sockaddr_ppp pppaddr;
|
||||
pppaddr.ppp_len = sizeof(struct sockaddr_ppp);
|
||||
pppaddr.ppp_family = AF_PPP;
|
||||
pppaddr.ppp_proto = PPPPROTO_CTL;
|
||||
pppaddr.ppp_cookie = 0;
|
||||
|
||||
if(connect(ppp_sockfd, (struct sockaddr *)&pppaddr, sizeof(struct sockaddr_ppp)) < 0) {
|
||||
tun_error("connecting ppp socket: %s", strerror(errno));
|
||||
close(ppp_sockfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tun_noerror();
|
||||
return ppp_sockfd;
|
||||
}
|
||||
|
||||
static int ppp_new_unit(int *unit_number) {
|
||||
int fd = ppp_new_instance();
|
||||
|
||||
if(fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// create ppp unit
|
||||
if(ioctl(fd, PPPIOCNEWUNIT, unit_number) < 0) {
|
||||
tun_error("creating ppp unit: %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tun_noerror();
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int ppp_setup_unit(int unit_fd) {
|
||||
// send traffic to program
|
||||
int flags = SC_LOOP_TRAFFIC;
|
||||
|
||||
if(ioctl(unit_fd, PPPIOCSFLAGS, &flags) < 0) {
|
||||
tun_error("setting ppp loopback mode: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// allow packets
|
||||
struct npioctl npi;
|
||||
npi.protocol = PPP_IP;
|
||||
npi.mode = NPMODE_PASS;
|
||||
|
||||
if(ioctl(unit_fd, PPPIOCSNPMODE, &npi) < 0) {
|
||||
tun_error("starting ppp unit: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tun_noerror();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_pcap() {
|
||||
if(pcap != NULL) {
|
||||
pcap_use_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
pcap = pcap_open_live("lo0", BUFSIZ, 0, 1, errbuf);
|
||||
pcap_use_count = 1;
|
||||
|
||||
if(pcap == NULL) {
|
||||
tun_error("opening pcap: %s", errbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tun_noerror();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void close_pcap() {
|
||||
if(pcap == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pcap_use_count--;
|
||||
|
||||
if(pcap_use_count == 0) {
|
||||
pcap_close(pcap);
|
||||
pcap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void allocate_data_buffer(int size) {
|
||||
if(data_buffer_length < size) {
|
||||
free(data_buffer);
|
||||
data_buffer_length = size;
|
||||
data_buffer = malloc(data_buffer_length);
|
||||
}
|
||||
}
|
||||
|
||||
static void make_device_name(tunemu_device device, int unit_number) {
|
||||
snprintf(device, sizeof(tunemu_device), "ppp%d", unit_number);
|
||||
}
|
||||
|
||||
static int check_device_name(tunemu_device device) {
|
||||
if(strlen(device) < 4) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unit_number = atoi(device + 3);
|
||||
|
||||
if(unit_number < 0 || unit_number > 999) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tunemu_device compare;
|
||||
make_device_name(compare, unit_number);
|
||||
|
||||
if(strcmp(device, compare) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tunemu_open(tunemu_device device) {
|
||||
int ppp_unit_number = -1;
|
||||
|
||||
if(device[0] != 0) {
|
||||
if(check_device_name(device) < 0) {
|
||||
tun_error("invalid device name \"%s\"", device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ppp_unit_number = atoi(device + 3);
|
||||
}
|
||||
|
||||
int ppp_unit_fd = ppp_new_unit(&ppp_unit_number);
|
||||
|
||||
if(ppp_unit_fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(ppp_setup_unit(ppp_unit_fd) < 0) {
|
||||
close(ppp_unit_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(open_pcap() < 0) {
|
||||
close(ppp_unit_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
make_device_name(device, ppp_unit_number);
|
||||
|
||||
return ppp_unit_fd;
|
||||
}
|
||||
|
||||
int tunemu_close(int ppp_sockfd) {
|
||||
int ret = close(ppp_sockfd);
|
||||
|
||||
if(ret == 0) {
|
||||
close_pcap();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tunemu_read(int ppp_sockfd, char *buffer, int length) {
|
||||
allocate_data_buffer(length + 2);
|
||||
|
||||
length = read(ppp_sockfd, data_buffer, length + 2);
|
||||
|
||||
if(length < 0) {
|
||||
tun_error("reading packet: %s", strerror(errno));
|
||||
return length;
|
||||
}
|
||||
|
||||
tun_noerror();
|
||||
|
||||
length -= 2;
|
||||
|
||||
if(length < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(buffer, data_buffer + 2, length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int tunemu_write(int ppp_sockfd, char *buffer, int length) {
|
||||
allocate_data_buffer(length + 4);
|
||||
|
||||
data_buffer[0] = 0x02;
|
||||
data_buffer[1] = 0x00;
|
||||
data_buffer[2] = 0x00;
|
||||
data_buffer[3] = 0x00;
|
||||
|
||||
memcpy(data_buffer + 4, buffer, length);
|
||||
|
||||
if(pcap == NULL) {
|
||||
tun_error("pcap not open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
length = pcap_inject(pcap, data_buffer, length + 4);
|
||||
|
||||
if(length < 0) {
|
||||
tun_error("injecting packet: %s", pcap_geterr(pcap));
|
||||
return length;
|
||||
}
|
||||
|
||||
tun_noerror();
|
||||
|
||||
length -= 4;
|
||||
|
||||
if(length < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
32
src/bsd/tunemu.h
Normal file
32
src/bsd/tunemu.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* tunemu - Tun device emulation for Darwin
|
||||
* Copyright (C) 2009 Friedrich Schöller <friedrich.schoeller@gmail.com>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TUNEMU_H
|
||||
#define TUNEMU_H
|
||||
|
||||
typedef char tunemu_device[7];
|
||||
|
||||
extern char tunemu_error[];
|
||||
|
||||
int tunemu_open(tunemu_device dev);
|
||||
int tunemu_close(int fd);
|
||||
int tunemu_read(int fd, char *buffer, int length);
|
||||
int tunemu_write(int fd, char *buffer, int length);
|
||||
|
||||
#endif
|
||||
602
src/conf.c
Normal file
602
src/conf.c
Normal file
|
|
@ -0,0 +1,602 @@
|
|||
/*
|
||||
conf.c -- configuration code
|
||||
Copyright (C) 1998 Robert van der Meulen
|
||||
1998-2005 Ivo Timmermans
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2010-2011 Julien Muchembled <jm@jmuchemb.eu>
|
||||
2000 Cris van Pelt
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "connection.h"
|
||||
#include "conf.h"
|
||||
#include "list.h"
|
||||
#include "logger.h"
|
||||
#include "netutl.h" /* for str2address */
|
||||
#include "protocol.h"
|
||||
#include "utils.h" /* for cp */
|
||||
#include "xalloc.h"
|
||||
|
||||
avl_tree_t *config_tree;
|
||||
|
||||
int pinginterval = 0; /* seconds between pings */
|
||||
int pingtimeout = 0; /* seconds to wait for response */
|
||||
char *confbase = NULL; /* directory in which all config files are */
|
||||
char *netname = NULL; /* name of the vpn network */
|
||||
list_t *cmdline_conf = NULL; /* global/host configuration values given at the command line */
|
||||
|
||||
|
||||
static int config_compare(const config_t *a, const config_t *b) {
|
||||
int result;
|
||||
|
||||
result = strcasecmp(a->variable, b->variable);
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* give priority to command line options */
|
||||
result = !b->file - !a->file;
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = a->line - b->line;
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
} else {
|
||||
return a->file ? strcmp(a->file, b->file) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void init_configuration(avl_tree_t **config_tree) {
|
||||
*config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
|
||||
}
|
||||
|
||||
void exit_configuration(avl_tree_t **config_tree) {
|
||||
avl_delete_tree(*config_tree);
|
||||
*config_tree = NULL;
|
||||
}
|
||||
|
||||
config_t *new_config(void) {
|
||||
return xmalloc_and_zero(sizeof(config_t));
|
||||
}
|
||||
|
||||
void free_config(config_t *cfg) {
|
||||
free(cfg->variable);
|
||||
free(cfg->value);
|
||||
free(cfg->file);
|
||||
free(cfg);
|
||||
}
|
||||
|
||||
void config_add(avl_tree_t *config_tree, config_t *cfg) {
|
||||
avl_insert(config_tree, cfg);
|
||||
}
|
||||
|
||||
config_t *lookup_config(const avl_tree_t *config_tree, char *variable) {
|
||||
config_t cfg, *found;
|
||||
|
||||
cfg.variable = variable;
|
||||
cfg.file = NULL;
|
||||
cfg.line = 0;
|
||||
|
||||
found = avl_search_closest_greater(config_tree, &cfg);
|
||||
|
||||
if(!found) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(strcasecmp(found->variable, variable)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg) {
|
||||
avl_node_t *node;
|
||||
config_t *found;
|
||||
|
||||
node = avl_search_node(config_tree, cfg);
|
||||
|
||||
if(node) {
|
||||
if(node->next) {
|
||||
found = node->next->data;
|
||||
|
||||
if(!strcasecmp(found->variable, cfg->variable)) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool get_config_bool(const config_t *cfg, bool *result) {
|
||||
if(!cfg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!strcasecmp(cfg->value, "yes")) {
|
||||
*result = true;
|
||||
return true;
|
||||
} else if(!strcasecmp(cfg->value, "no")) {
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_config_int(const config_t *cfg, int *result) {
|
||||
if(!cfg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sscanf(cfg->value, "%d", result) == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_config_string(const config_t *cfg, char **result) {
|
||||
if(!cfg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = xstrdup(cfg->value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_config_address(const config_t *cfg, struct addrinfo **result) {
|
||||
struct addrinfo *ai;
|
||||
|
||||
if(!cfg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ai = str2addrinfo(cfg->value, NULL, 0);
|
||||
|
||||
if(ai) {
|
||||
*result = ai;
|
||||
return true;
|
||||
}
|
||||
|
||||
logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_config_subnet(const config_t *cfg, subnet_t **result) {
|
||||
subnet_t subnet = {0};
|
||||
|
||||
if(!cfg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!str2net(&subnet, cfg->value)) {
|
||||
logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Teach newbies what subnets are... */
|
||||
|
||||
if(((subnet.type == SUBNET_IPV4)
|
||||
&& !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
|
||||
|| ((subnet.type == SUBNET_IPV6)
|
||||
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
|
||||
logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
return false;
|
||||
}
|
||||
|
||||
*(*result = new_subnet()) = subnet;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Read exactly one line and strip the trailing newline if any.
|
||||
*/
|
||||
static char *readline(FILE *fp, char *buf, size_t buflen) {
|
||||
char *newline = NULL;
|
||||
char *p;
|
||||
|
||||
if(feof(fp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = fgets(buf, buflen, fp);
|
||||
|
||||
if(!p) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newline = strchr(p, '\n');
|
||||
|
||||
if(!newline) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
*newline = '\0'; /* kill newline */
|
||||
|
||||
if(newline > p && newline[-1] == '\r') { /* and carriage return if necessary */
|
||||
newline[-1] = '\0';
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
config_t *parse_config_line(char *line, const char *fname, int lineno) {
|
||||
config_t *cfg;
|
||||
int len;
|
||||
char *variable, *value, *eol;
|
||||
variable = value = line;
|
||||
|
||||
eol = line + strlen(line);
|
||||
|
||||
while(strchr("\t ", *--eol)) {
|
||||
*eol = '\0';
|
||||
}
|
||||
|
||||
len = strcspn(value, "\t =");
|
||||
value += len;
|
||||
value += strspn(value, "\t ");
|
||||
|
||||
if(*value == '=') {
|
||||
value++;
|
||||
value += strspn(value, "\t ");
|
||||
}
|
||||
|
||||
variable[len] = '\0';
|
||||
|
||||
if(!*value) {
|
||||
const char err[] = "No value for variable";
|
||||
|
||||
if(fname)
|
||||
logger(LOG_ERR, "%s `%s' on line %d while reading config file %s",
|
||||
err, variable, lineno, fname);
|
||||
else
|
||||
logger(LOG_ERR, "%s `%s' in command line option %d",
|
||||
err, variable, lineno);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cfg = new_config();
|
||||
cfg->variable = xstrdup(variable);
|
||||
cfg->value = xstrdup(value);
|
||||
cfg->file = fname ? xstrdup(fname) : NULL;
|
||||
cfg->line = lineno;
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
/*
|
||||
Parse a configuration file and put the results in the configuration tree
|
||||
starting at *base.
|
||||
*/
|
||||
bool read_config_file(avl_tree_t *config_tree, const char *fname) {
|
||||
FILE *fp;
|
||||
char buffer[MAX_STRING_SIZE];
|
||||
char *line;
|
||||
int lineno = 0;
|
||||
bool ignore = false;
|
||||
config_t *cfg;
|
||||
bool result = false;
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
line = readline(fp, buffer, sizeof(buffer));
|
||||
|
||||
if(!line) {
|
||||
if(feof(fp)) {
|
||||
result = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
lineno++;
|
||||
|
||||
if(!*line || *line == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ignore) {
|
||||
if(!strncmp(line, "-----END", 8)) {
|
||||
ignore = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strncmp(line, "-----BEGIN", 10)) {
|
||||
ignore = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
cfg = parse_config_line(line, fname, lineno);
|
||||
|
||||
if(!cfg) {
|
||||
break;
|
||||
}
|
||||
|
||||
config_add(config_tree, cfg);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void read_config_options(avl_tree_t *config_tree, const char *prefix) {
|
||||
size_t prefix_len = prefix ? strlen(prefix) : 0;
|
||||
|
||||
for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
|
||||
const config_t *cfg = node->data;
|
||||
|
||||
if(!prefix) {
|
||||
if(strchr(cfg->variable, '.')) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if(strncmp(prefix, cfg->variable, prefix_len) ||
|
||||
cfg->variable[prefix_len] != '.') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
config_t *new = new_config();
|
||||
|
||||
if(prefix) {
|
||||
new->variable = xstrdup(cfg->variable + prefix_len + 1);
|
||||
} else {
|
||||
new->variable = xstrdup(cfg->variable);
|
||||
}
|
||||
|
||||
new->value = xstrdup(cfg->value);
|
||||
new->file = NULL;
|
||||
new->line = cfg->line;
|
||||
|
||||
config_add(config_tree, new);
|
||||
}
|
||||
}
|
||||
|
||||
bool read_server_config(void) {
|
||||
char fname[PATH_MAX];
|
||||
bool x;
|
||||
|
||||
read_config_options(config_tree, NULL);
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s/tinc.conf", confbase);
|
||||
errno = 0;
|
||||
x = read_config_file(config_tree, fname);
|
||||
|
||||
// We will try to read the conf files in the "conf.d" dir
|
||||
if(x) {
|
||||
char dname[PATH_MAX];
|
||||
snprintf(dname, sizeof(dname), "%s/conf.d", confbase);
|
||||
DIR *dir = opendir(dname);
|
||||
|
||||
// If we can find this dir
|
||||
if(dir) {
|
||||
struct dirent *ep;
|
||||
|
||||
// We list all the files in it
|
||||
while(x && (ep = readdir(dir))) {
|
||||
size_t l = strlen(ep->d_name);
|
||||
|
||||
// And we try to read the ones that end with ".conf"
|
||||
if(l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) {
|
||||
if((size_t)snprintf(fname, sizeof(fname), "%s/%s", dname, ep->d_name) >= sizeof(fname)) {
|
||||
logger(LOG_ERR, "Pathname too long: %s/%s", dname, ep->d_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
x = read_config_file(config_tree, fname);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
if(!x && errno) {
|
||||
logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
bool read_connection_config(connection_t *c) {
|
||||
char fname[PATH_MAX];
|
||||
bool x;
|
||||
|
||||
read_config_options(c->config_tree, c->name);
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s/hosts/%s", confbase, c->name);
|
||||
x = read_config_file(c->config_tree, fname);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static void disable_old_keys(const char *filename) {
|
||||
char tmpfile[PATH_MAX] = "";
|
||||
char buf[1024];
|
||||
bool disabled = false;
|
||||
FILE *r, *w;
|
||||
|
||||
r = fopen(filename, "r");
|
||||
|
||||
if(!r) {
|
||||
return;
|
||||
}
|
||||
|
||||
int len = snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
|
||||
|
||||
if(len < 0 || len >= PATH_MAX) {
|
||||
fprintf(stderr, "Pathname too long: %s.tmp\n", filename);
|
||||
w = NULL;
|
||||
} else {
|
||||
w = fopen(tmpfile, "w");
|
||||
}
|
||||
|
||||
while(fgets(buf, sizeof(buf), r)) {
|
||||
if(!strncmp(buf, "-----BEGIN RSA", 14)) {
|
||||
buf[11] = 'O';
|
||||
buf[12] = 'L';
|
||||
buf[13] = 'D';
|
||||
disabled = true;
|
||||
} else if(!strncmp(buf, "-----END RSA", 12)) {
|
||||
buf[ 9] = 'O';
|
||||
buf[10] = 'L';
|
||||
buf[11] = 'D';
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
if(w && fputs(buf, w) < 0) {
|
||||
disabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(w) {
|
||||
fclose(w);
|
||||
}
|
||||
|
||||
fclose(r);
|
||||
|
||||
if(!w && disabled) {
|
||||
fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(disabled) {
|
||||
#ifdef HAVE_MINGW
|
||||
// We cannot atomically replace files on Windows.
|
||||
char bakfile[PATH_MAX] = "";
|
||||
snprintf(bakfile, sizeof(bakfile), "%s.bak", filename);
|
||||
|
||||
if(rename(filename, bakfile) || rename(tmpfile, filename)) {
|
||||
rename(bakfile, filename);
|
||||
#else
|
||||
|
||||
if(rename(tmpfile, filename)) {
|
||||
#endif
|
||||
fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
|
||||
} else {
|
||||
#ifdef HAVE_MINGW
|
||||
unlink(bakfile);
|
||||
#endif
|
||||
fprintf(stderr, "Warning: old key(s) found and disabled.\n");
|
||||
}
|
||||
}
|
||||
|
||||
unlink(tmpfile);
|
||||
}
|
||||
|
||||
FILE *ask_and_open(const char *filename, const char *what) {
|
||||
FILE *r;
|
||||
char directory[PATH_MAX];
|
||||
char line[PATH_MAX];
|
||||
char abspath[PATH_MAX];
|
||||
const char *fn;
|
||||
|
||||
/* Check stdin and stdout */
|
||||
if(!isatty(0) || !isatty(1)) {
|
||||
/* Argh, they are running us from a script or something. Write
|
||||
the files to the current directory and let them burn in hell
|
||||
for ever. */
|
||||
fn = filename;
|
||||
} else {
|
||||
/* Ask for a file and/or directory name. */
|
||||
fprintf(stdout, "Please enter a file to save %s to [%s]: ",
|
||||
what, filename);
|
||||
fflush(stdout);
|
||||
|
||||
fn = readline(stdin, line, sizeof(line));
|
||||
|
||||
if(!fn) {
|
||||
fprintf(stderr, "Error while reading stdin: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!strlen(fn))
|
||||
/* User just pressed enter. */
|
||||
{
|
||||
fn = filename;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
|
||||
if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
|
||||
#else
|
||||
|
||||
if(fn[0] != '/') {
|
||||
#endif
|
||||
/* The directory is a relative path or a filename. */
|
||||
getcwd(directory, sizeof(directory));
|
||||
|
||||
if((size_t)snprintf(abspath, sizeof(abspath), "%s/%s", directory, fn) >= sizeof(abspath)) {
|
||||
fprintf(stderr, "Pathname too long: %s/%s\n", directory, fn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn = abspath;
|
||||
}
|
||||
|
||||
umask(0077); /* Disallow everything for group and other */
|
||||
|
||||
disable_old_keys(fn);
|
||||
|
||||
/* Open it first to keep the inode busy */
|
||||
|
||||
r = fopen(fn, "a");
|
||||
|
||||
if(!r) {
|
||||
fprintf(stderr, "Error opening file `%s': %s\n",
|
||||
fn, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
67
src/conf.h
Normal file
67
src/conf.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef TINC_CONF_H
|
||||
#define TINC_CONF_H
|
||||
|
||||
/*
|
||||
conf.h -- header for conf.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "list.h"
|
||||
|
||||
typedef struct config_t {
|
||||
char *variable;
|
||||
char *value;
|
||||
char *file;
|
||||
int line;
|
||||
} config_t;
|
||||
|
||||
#include "subnet.h"
|
||||
|
||||
extern avl_tree_t *config_tree;
|
||||
|
||||
extern int pinginterval;
|
||||
extern int pingtimeout;
|
||||
extern int maxtimeout;
|
||||
extern int mintimeout;
|
||||
extern bool bypass_security;
|
||||
extern char *confbase;
|
||||
extern char *netname;
|
||||
extern list_t *cmdline_conf;
|
||||
|
||||
extern void init_configuration(avl_tree_t **config_tree);
|
||||
extern void exit_configuration(avl_tree_t **config_tree);
|
||||
extern config_t *new_config(void) __attribute__((__malloc__));
|
||||
extern void free_config(config_t *cfg);
|
||||
extern void config_add(avl_tree_t *config_tree, config_t *cfg);
|
||||
extern config_t *lookup_config(const avl_tree_t *config_tree, char *variable);
|
||||
extern config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg);
|
||||
extern bool get_config_bool(const config_t *cfg, bool *result);
|
||||
extern bool get_config_int(const config_t *cfg, int *result);
|
||||
extern bool get_config_string(const config_t *cfg, char **result);
|
||||
extern bool get_config_address(const config_t *cfg, struct addrinfo **result);
|
||||
extern bool get_config_subnet(const config_t *cfg, struct subnet_t **result);
|
||||
|
||||
extern config_t *parse_config_line(char *line, const char *fname, int lineno);
|
||||
extern bool read_config_file(avl_tree_t *config_tree, const char *fname);
|
||||
extern void read_config_options(avl_tree_t *config_tree, const char *prefix);
|
||||
extern bool read_server_config(void);
|
||||
extern bool read_connection_config(struct connection_t *c);
|
||||
extern FILE *ask_and_open(const char *fname, const char *what);
|
||||
|
||||
#endif
|
||||
151
src/connection.c
Normal file
151
src/connection.c
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
connection.c -- connection list management
|
||||
Copyright (C) 2000-2016 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
2008 Max Rijevski <maksuf@gmail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "conf.h"
|
||||
#include "logger.h"
|
||||
#include "subnet.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
avl_tree_t *connection_tree; /* Meta connections */
|
||||
connection_t *everyone;
|
||||
|
||||
static int connection_compare(const connection_t *a, const connection_t *b) {
|
||||
return a < b ? -1 : a == b ? 0 : 1;
|
||||
}
|
||||
|
||||
void init_connections(void) {
|
||||
connection_tree = avl_alloc_tree((avl_compare_t) connection_compare, (avl_action_t) free_connection);
|
||||
everyone = new_connection();
|
||||
everyone->name = xstrdup("everyone");
|
||||
everyone->hostname = xstrdup("BROADCAST");
|
||||
}
|
||||
|
||||
void exit_connections(void) {
|
||||
avl_delete_tree(connection_tree);
|
||||
free_connection(everyone);
|
||||
}
|
||||
|
||||
connection_t *new_connection(void) {
|
||||
connection_t *c;
|
||||
|
||||
c = xmalloc_and_zero(sizeof(connection_t));
|
||||
|
||||
if(!c) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gettimeofday(&c->start, NULL);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void free_connection_partially(connection_t *c) {
|
||||
free(c->inkey);
|
||||
free(c->outkey);
|
||||
free(c->mychallenge);
|
||||
free(c->hischallenge);
|
||||
free(c->outbuf);
|
||||
|
||||
c->inkey = NULL;
|
||||
c->outkey = NULL;
|
||||
c->mychallenge = NULL;
|
||||
c->hischallenge = NULL;
|
||||
c->outbuf = NULL;
|
||||
|
||||
c->status.pinged = false;
|
||||
c->status.active = false;
|
||||
c->status.connecting = false;
|
||||
c->status.timeout = false;
|
||||
c->status.encryptout = false;
|
||||
c->status.decryptin = false;
|
||||
c->status.mst = false;
|
||||
|
||||
c->options = 0;
|
||||
c->buflen = 0;
|
||||
c->reqlen = 0;
|
||||
c->tcplen = 0;
|
||||
c->allow_request = 0;
|
||||
c->outbuflen = 0;
|
||||
c->outbufsize = 0;
|
||||
c->outbufstart = 0;
|
||||
c->last_ping_time = 0;
|
||||
c->last_flushed_time = 0;
|
||||
c->inbudget = 0;
|
||||
c->outbudget = 0;
|
||||
|
||||
if(c->inctx) {
|
||||
EVP_CIPHER_CTX_reset(c->inctx);
|
||||
free(c->inctx);
|
||||
c->inctx = NULL;
|
||||
}
|
||||
|
||||
if(c->outctx) {
|
||||
EVP_CIPHER_CTX_reset(c->outctx);
|
||||
free(c->outctx);
|
||||
c->outctx = NULL;
|
||||
}
|
||||
|
||||
if(c->rsa_key) {
|
||||
EVP_PKEY_free(c->rsa_key);
|
||||
c->rsa_key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void free_connection(connection_t *c) {
|
||||
free_connection_partially(c);
|
||||
|
||||
free(c->name);
|
||||
free(c->hostname);
|
||||
|
||||
if(c->config_tree) {
|
||||
exit_configuration(&c->config_tree);
|
||||
}
|
||||
|
||||
free(c);
|
||||
}
|
||||
|
||||
void connection_add(connection_t *c) {
|
||||
avl_insert(connection_tree, c);
|
||||
}
|
||||
|
||||
void connection_del(connection_t *c) {
|
||||
avl_delete(connection_tree, c);
|
||||
}
|
||||
|
||||
void dump_connections(void) {
|
||||
avl_node_t *node;
|
||||
connection_t *c;
|
||||
|
||||
logger(LOG_DEBUG, "Connections:");
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
logger(LOG_DEBUG, " %s at %s options %x socket %d status %04x outbuf %d/%d/%d",
|
||||
c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof(c->status)),
|
||||
c->outbufsize, c->outbufstart, c->outbuflen);
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, "End of connections.");
|
||||
}
|
||||
118
src/connection.h
Normal file
118
src/connection.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#ifndef TINC_CONNECTION_H
|
||||
#define TINC_CONNECTION_H
|
||||
|
||||
/*
|
||||
connection.h -- header for connection.c
|
||||
Copyright (C) 2000-2016 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "avl_tree.h"
|
||||
|
||||
#define OPTION_INDIRECT 0x0001
|
||||
#define OPTION_TCPONLY 0x0002
|
||||
#define OPTION_PMTU_DISCOVERY 0x0004
|
||||
#define OPTION_CLAMP_MSS 0x0008
|
||||
|
||||
typedef struct connection_status_t {
|
||||
unsigned int pinged: 1; /* sent ping */
|
||||
unsigned int active: 1; /* 1 if active.. */
|
||||
unsigned int connecting: 1; /* 1 if we are waiting for a non-blocking connect() to finish */
|
||||
unsigned int unused_termreq: 1; /* the termination of this connection was requested */
|
||||
unsigned int remove: 1; /* Set to 1 if you want this connection removed */
|
||||
unsigned int timeout: 1; /* 1 if gotten timeout */
|
||||
unsigned int encryptout: 1; /* 1 if we can encrypt outgoing traffic */
|
||||
unsigned int decryptin: 1; /* 1 if we have to decrypt incoming traffic */
|
||||
unsigned int mst: 1; /* 1 if this connection is part of a minimum spanning tree */
|
||||
unsigned int proxy_passed: 1; /* 1 if we are connecting via a proxy and we have finished talking with it */
|
||||
unsigned int tarpit: 1; /* 1 if the connection should be added to the tarpit */
|
||||
unsigned int unused: 21;
|
||||
} connection_status_t;
|
||||
|
||||
#include "edge.h"
|
||||
#include "net.h"
|
||||
#include "node.h"
|
||||
|
||||
typedef struct connection_t {
|
||||
char *name; /* name he claims to have */
|
||||
|
||||
union sockaddr_t address; /* his real (internet) ip */
|
||||
char *hostname; /* the hostname of its real ip */
|
||||
int protocol_version; /* used protocol */
|
||||
|
||||
int socket; /* socket used for this connection */
|
||||
uint32_t options; /* options for this connection */
|
||||
connection_status_t status; /* status info */
|
||||
int estimated_weight; /* estimation for the weight of the edge for this connection */
|
||||
struct timeval start; /* time this connection was started, used for above estimation */
|
||||
struct outgoing_t *outgoing; /* used to keep track of outgoing connections */
|
||||
|
||||
struct node_t *node; /* node associated with the other end */
|
||||
struct edge_t *edge; /* edge associated with this connection */
|
||||
|
||||
EVP_PKEY *rsa_key; /* his public/private key */
|
||||
const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */
|
||||
const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */
|
||||
EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */
|
||||
EVP_CIPHER_CTX *outctx; /* Context of encrypted meta data that will be sent from us to him */
|
||||
uint64_t inbudget; /* Encrypted bytes send budget */
|
||||
uint64_t outbudget; /* Encrypted bytes receive budget */
|
||||
char *inkey; /* His symmetric meta key + iv */
|
||||
char *outkey; /* Our symmetric meta key + iv */
|
||||
int inkeylength; /* Length of his key + iv */
|
||||
int outkeylength; /* Length of our key + iv */
|
||||
const EVP_MD *indigest;
|
||||
const EVP_MD *outdigest;
|
||||
int inmaclength;
|
||||
int outmaclength;
|
||||
int incompression;
|
||||
int outcompression;
|
||||
char *mychallenge; /* challenge we received from him */
|
||||
char *hischallenge; /* challenge we sent to him */
|
||||
|
||||
char buffer[MAXBUFSIZE]; /* metadata input buffer */
|
||||
int buflen; /* bytes read into buffer */
|
||||
int reqlen; /* length of incoming request */
|
||||
length_t tcplen; /* length of incoming TCPpacket */
|
||||
int allow_request; /* defined if there's only one request possible */
|
||||
|
||||
char *outbuf; /* metadata output buffer */
|
||||
int outbufstart; /* index of first meaningful byte in output buffer */
|
||||
int outbuflen; /* number of meaningful bytes in output buffer */
|
||||
int outbufsize; /* number of bytes allocated to output buffer */
|
||||
|
||||
time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */
|
||||
time_t last_flushed_time; /* last time buffer was empty. Only meaningful if outbuflen > 0 */
|
||||
|
||||
avl_tree_t *config_tree; /* Pointer to configuration tree belonging to him */
|
||||
} connection_t;
|
||||
|
||||
extern avl_tree_t *connection_tree;
|
||||
extern connection_t *everyone;
|
||||
|
||||
extern void init_connections(void);
|
||||
extern void exit_connections(void);
|
||||
extern connection_t *new_connection(void) __attribute__((__malloc__));
|
||||
extern void free_connection(connection_t *c);
|
||||
extern void free_connection_partially(connection_t *c);
|
||||
extern void connection_add(connection_t *c);
|
||||
extern void connection_del(connection_t *c);
|
||||
extern void dump_connections(void);
|
||||
|
||||
#endif
|
||||
287
src/cygwin/device.c
Normal file
287
src/cygwin/device.c
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a Cygwin environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
#include "../net.h"
|
||||
|
||||
#include <w32api/windows.h>
|
||||
#include <w32api/winioctl.h>
|
||||
|
||||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
#include "../mingw/common.h"
|
||||
|
||||
int device_fd = -1;
|
||||
static HANDLE device_handle = INVALID_HANDLE_VALUE;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static const char *device_info = "Windows tap device";
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static pid_t reader_pid;
|
||||
static int sp[2];
|
||||
|
||||
static bool setup_device(void) {
|
||||
HKEY key, key2;
|
||||
int i, err;
|
||||
|
||||
char regpath[1024];
|
||||
char adapterid[1024];
|
||||
char adaptername[1024];
|
||||
char tapname[1024];
|
||||
char gelukt = 0;
|
||||
long len;
|
||||
|
||||
bool found = false;
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
||||
get_config_string(lookup_config(config_tree, "Interface"), &iface);
|
||||
|
||||
if(device && iface) {
|
||||
logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
|
||||
}
|
||||
|
||||
/* Open registry and look for network adapters */
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
||||
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
for(i = 0; ; i++) {
|
||||
len = sizeof(adapterid);
|
||||
|
||||
if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find out more about this adapter */
|
||||
|
||||
snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
len = sizeof(adaptername);
|
||||
err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
|
||||
|
||||
RegCloseKey(key2);
|
||||
|
||||
if(err) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(device) {
|
||||
if(!strcmp(device, adapterid)) {
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(iface) {
|
||||
if(!strcmp(iface, adaptername)) {
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
|
||||
device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
|
||||
if(device_handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(device_handle);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(key);
|
||||
|
||||
if(!found) {
|
||||
logger(LOG_ERR, "No Windows tap device found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!device) {
|
||||
device = xstrdup(adapterid);
|
||||
}
|
||||
|
||||
if(!iface) {
|
||||
iface = xstrdup(adaptername);
|
||||
}
|
||||
|
||||
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
|
||||
|
||||
/* Now we are going to open this device twice: once for reading and once for writing.
|
||||
We do this because apparently it isn't possible to check for activity in the select() loop.
|
||||
Furthermore I don't really know how to do it the "Windows" way. */
|
||||
|
||||
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
|
||||
logger(LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The parent opens the tap device for writing. */
|
||||
|
||||
device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
device_fd = sp[0];
|
||||
|
||||
/* Get MAC address from tap device */
|
||||
|
||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
|
||||
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(routing_mode == RMODE_ROUTER) {
|
||||
overwrite_mac = 1;
|
||||
}
|
||||
|
||||
/* Now we start the child */
|
||||
|
||||
reader_pid = fork();
|
||||
|
||||
if(reader_pid == -1) {
|
||||
logger(LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!reader_pid) {
|
||||
/* The child opens the tap device for reading, blocking.
|
||||
It passes everything it reads to the socket. */
|
||||
|
||||
char buf[MTU];
|
||||
long lenin;
|
||||
|
||||
CloseHandle(device_handle);
|
||||
|
||||
device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
|
||||
buf[0] = 0;
|
||||
write(sp[1], buf, 1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, "Tap reader forked and running.");
|
||||
|
||||
/* Notify success */
|
||||
|
||||
buf[0] = 1;
|
||||
write(sp[1], buf, 1);
|
||||
|
||||
/* Pass packets */
|
||||
|
||||
for(;;) {
|
||||
ReadFile(device_handle, buf, MTU, &lenin, NULL);
|
||||
write(sp[1], buf, lenin);
|
||||
}
|
||||
}
|
||||
|
||||
read(device_fd, &gelukt, 1);
|
||||
|
||||
if(gelukt != 1) {
|
||||
logger(LOG_DEBUG, "Tap reader failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(sp[0]);
|
||||
close(sp[1]);
|
||||
CloseHandle(device_handle);
|
||||
|
||||
kill(reader_pid, SIGKILL);
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin;
|
||||
|
||||
if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->len = lenin;
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
long lenout;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(!WriteFile(device_handle, packet->data, packet->len, &lenout, NULL)) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
47
src/device.h
Normal file
47
src/device.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef TINC_DEVICE_H
|
||||
#define TINC_DEVICE_H
|
||||
|
||||
/*
|
||||
device.h -- generic header for device.c
|
||||
Copyright (C) 2001-2005 Ivo Timmermans
|
||||
2001-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
|
||||
extern int device_fd;
|
||||
extern char *device;
|
||||
|
||||
extern char *iface;
|
||||
|
||||
typedef struct devops_t {
|
||||
bool (*setup)(void);
|
||||
void (*close)(void);
|
||||
bool (*read)(struct vpn_packet_t *packet);
|
||||
bool (*write)(struct vpn_packet_t *packet);
|
||||
void (*dump_stats)(void);
|
||||
} devops_t;
|
||||
|
||||
extern const devops_t os_devops;
|
||||
extern const devops_t dummy_devops;
|
||||
extern const devops_t raw_socket_devops;
|
||||
extern const devops_t multicast_devops;
|
||||
extern const devops_t uml_devops;
|
||||
extern const devops_t vde_devops;
|
||||
extern devops_t devops;
|
||||
|
||||
#endif
|
||||
142
src/dropin.c
Normal file
142
src/dropin.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
dropin.c -- a set of drop-in replacements for libc functions
|
||||
Copyright (C) 2000-2005 Ivo Timmermans,
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
/*
|
||||
Replacement for the daemon() function.
|
||||
|
||||
The daemon() function is for programs wishing to detach themselves
|
||||
from the controlling terminal and run in the background as system
|
||||
daemons.
|
||||
|
||||
Unless the argument nochdir is non-zero, daemon() changes the
|
||||
current working directory to the root (``/'').
|
||||
|
||||
Unless the argument noclose is non-zero, daemon() will redirect
|
||||
standard input, standard output and standard error to /dev/null.
|
||||
*/
|
||||
int daemon(int nochdir, int noclose) {
|
||||
#ifdef HAVE_FORK
|
||||
pid_t pid;
|
||||
int fd;
|
||||
|
||||
pid = fork();
|
||||
|
||||
/* Check if forking failed */
|
||||
if(pid < 0) {
|
||||
perror("fork");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* If we are the parent, terminate */
|
||||
if(pid) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Detach by becoming the new process group leader */
|
||||
if(setsid() < 0) {
|
||||
perror("setsid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Change working directory to the root (to avoid keeping mount
|
||||
points busy) */
|
||||
if(!nochdir) {
|
||||
chdir("/");
|
||||
}
|
||||
|
||||
/* Redirect stdin/out/err to /dev/null */
|
||||
if(!noclose) {
|
||||
fd = open("/dev/null", O_RDWR);
|
||||
|
||||
if(fd < 0) {
|
||||
perror("opening /dev/null");
|
||||
return -1;
|
||||
} else {
|
||||
dup2(fd, 0);
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int asprintf(char **buf, const char *fmt, ...) {
|
||||
int result;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
result = vasprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
int vasprintf(char **buf, const char *fmt, va_list ap) {
|
||||
int status;
|
||||
va_list aq;
|
||||
int len;
|
||||
|
||||
len = 4096;
|
||||
*buf = xmalloc(len);
|
||||
|
||||
va_copy(aq, ap);
|
||||
status = vsnprintf(*buf, len, fmt, aq);
|
||||
buf[len - 1] = 0;
|
||||
va_end(aq);
|
||||
|
||||
if(status >= 0) {
|
||||
*buf = xrealloc(*buf, status + 1);
|
||||
}
|
||||
|
||||
if(status > len - 1) {
|
||||
len = status;
|
||||
va_copy(aq, ap);
|
||||
status = vsnprintf(*buf, len, fmt, aq);
|
||||
va_end(aq);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
int gettimeofday(struct timeval *tv, void *tz) {
|
||||
tv->tv_sec = time(NULL);
|
||||
tv->tv_usec = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_USLEEP
|
||||
int usleep(long long usec) {
|
||||
struct timeval tv = {usec / 1000000, (usec / 1000) % 1000};
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
48
src/dropin.h
Normal file
48
src/dropin.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef TINC_DROPIN_H
|
||||
#define TINC_DROPIN_H
|
||||
|
||||
/*
|
||||
dropin.h -- header file for dropin.c
|
||||
Copyright (C) 2000-2005 Ivo Timmermans,
|
||||
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "fake-getaddrinfo.h"
|
||||
#include "fake-getnameinfo.h"
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
extern int daemon(int nochdir, int noclose);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GET_CURRENT_DIR_NAME
|
||||
extern char *get_current_dir_name(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
extern int asprintf(char **buf, const char *fmt, ...);
|
||||
extern int vasprintf(char **buf, const char *fmt, va_list ap);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
extern int gettimeofday(struct timeval *tv, void *tz);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_USLEEP
|
||||
extern int usleep(long long usec);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
66
src/dummy_device.c
Normal file
66
src/dummy_device.c
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
device.c -- Dummy device
|
||||
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static const char *device_info = "dummy device";
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
device = xstrdup("dummy");
|
||||
iface = xstrdup("dummy");
|
||||
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
free(device);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
(void)packet;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
device_total_out += packet->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t dummy_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
133
src/edge.c
Normal file
133
src/edge.c
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
edge.c -- edge tree management
|
||||
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "edge.h"
|
||||
#include "logger.h"
|
||||
#include "netutl.h"
|
||||
#include "node.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
|
||||
|
||||
static int edge_compare(const edge_t *a, const edge_t *b) {
|
||||
return strcmp(a->to->name, b->to->name);
|
||||
}
|
||||
|
||||
static int edge_weight_compare(const edge_t *a, const edge_t *b) {
|
||||
int result;
|
||||
|
||||
result = a->weight - b->weight;
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = strcmp(a->from->name, b->from->name);
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return strcmp(a->to->name, b->to->name);
|
||||
}
|
||||
|
||||
void init_edges(void) {
|
||||
edge_weight_tree = avl_alloc_tree((avl_compare_t) edge_weight_compare, NULL);
|
||||
}
|
||||
|
||||
avl_tree_t *new_edge_tree(void) {
|
||||
return avl_alloc_tree((avl_compare_t) edge_compare, (avl_action_t) free_edge);
|
||||
}
|
||||
|
||||
void free_edge_tree(avl_tree_t *edge_tree) {
|
||||
avl_delete_tree(edge_tree);
|
||||
}
|
||||
|
||||
void exit_edges(void) {
|
||||
avl_delete_tree(edge_weight_tree);
|
||||
}
|
||||
|
||||
/* Creation and deletion of connection elements */
|
||||
|
||||
edge_t *new_edge(void) {
|
||||
return xmalloc_and_zero(sizeof(edge_t));
|
||||
}
|
||||
|
||||
void free_edge(edge_t *e) {
|
||||
sockaddrfree(&e->address);
|
||||
|
||||
free(e);
|
||||
}
|
||||
|
||||
void edge_add(edge_t *e) {
|
||||
avl_insert(edge_weight_tree, e);
|
||||
avl_insert(e->from->edge_tree, e);
|
||||
|
||||
e->reverse = lookup_edge(e->to, e->from);
|
||||
|
||||
if(e->reverse) {
|
||||
e->reverse->reverse = e;
|
||||
}
|
||||
}
|
||||
|
||||
void edge_del(edge_t *e) {
|
||||
if(e->reverse) {
|
||||
e->reverse->reverse = NULL;
|
||||
}
|
||||
|
||||
avl_delete(edge_weight_tree, e);
|
||||
avl_delete(e->from->edge_tree, e);
|
||||
}
|
||||
|
||||
edge_t *lookup_edge(node_t *from, node_t *to) {
|
||||
edge_t v;
|
||||
|
||||
v.from = from;
|
||||
v.to = to;
|
||||
|
||||
return avl_search(from->edge_tree, &v);
|
||||
}
|
||||
|
||||
void dump_edges(void) {
|
||||
avl_node_t *node, *node2;
|
||||
node_t *n;
|
||||
edge_t *e;
|
||||
char *address;
|
||||
|
||||
logger(LOG_DEBUG, "Edges:");
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
|
||||
for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
|
||||
e = node2->data;
|
||||
address = sockaddr2hostname(&e->address);
|
||||
logger(LOG_DEBUG, " %s to %s at %s options %x weight %d",
|
||||
e->from->name, e->to->name, address, e->options, e->weight);
|
||||
free(address);
|
||||
}
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, "End of edges.");
|
||||
}
|
||||
54
src/edge.h
Normal file
54
src/edge.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef TINC_EDGE_H
|
||||
#define TINC_EDGE_H
|
||||
|
||||
/*
|
||||
edge.h -- header for edge.c
|
||||
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "connection.h"
|
||||
#include "net.h"
|
||||
#include "node.h"
|
||||
|
||||
typedef struct edge_t {
|
||||
struct node_t *from;
|
||||
struct node_t *to;
|
||||
sockaddr_t address;
|
||||
|
||||
uint32_t options; /* options turned on for this edge */
|
||||
int weight; /* weight of this edge */
|
||||
|
||||
struct connection_t *connection; /* connection associated with this edge, if available */
|
||||
struct edge_t *reverse; /* edge in the opposite direction, if available */
|
||||
} edge_t;
|
||||
|
||||
extern avl_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */
|
||||
|
||||
extern void init_edges(void);
|
||||
extern void exit_edges(void);
|
||||
extern edge_t *new_edge(void) __attribute__((__malloc__));
|
||||
extern void free_edge(edge_t *e);
|
||||
extern avl_tree_t *new_edge_tree(void) __attribute__((__malloc__));
|
||||
extern void free_edge_tree(avl_tree_t *edge_tree);
|
||||
extern void edge_add(edge_t *e);
|
||||
extern void edge_del(edge_t *e);
|
||||
extern edge_t *lookup_edge(struct node_t *from, struct node_t *to);
|
||||
extern void dump_edges(void);
|
||||
|
||||
#endif
|
||||
89
src/ethernet.h
Normal file
89
src/ethernet.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#ifndef TINC_ETHERNET_H
|
||||
#define TINC_ETHERNET_H
|
||||
|
||||
/*
|
||||
ethernet.h -- missing Ethernet related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef ETH_ALEN
|
||||
#define ETH_ALEN 6
|
||||
#endif
|
||||
|
||||
#ifndef ARPHRD_ETHER
|
||||
#define ARPHRD_ETHER 1
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_IP
|
||||
#define ETH_P_IP 0x0800
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_ARP
|
||||
#define ETH_P_ARP 0x0806
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_IPV6
|
||||
#define ETH_P_IPV6 0x86DD
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_8021Q
|
||||
#define ETH_P_8021Q 0x8100
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ETHER_HEADER
|
||||
struct ether_header {
|
||||
uint8_t ether_dhost[ETH_ALEN];
|
||||
uint8_t ether_shost[ETH_ALEN];
|
||||
uint16_t ether_type;
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ARPHDR
|
||||
struct arphdr {
|
||||
uint16_t ar_hrd;
|
||||
uint16_t ar_pro;
|
||||
uint8_t ar_hln;
|
||||
uint8_t ar_pln;
|
||||
uint16_t ar_op;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define ARPOP_REQUEST 1
|
||||
#define ARPOP_REPLY 2
|
||||
#define ARPOP_RREQUEST 3
|
||||
#define ARPOP_RREPLY 4
|
||||
#define ARPOP_InREQUEST 8
|
||||
#define ARPOP_InREPLY 9
|
||||
#define ARPOP_NAK 10
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ETHER_ARP
|
||||
struct ether_arp {
|
||||
struct arphdr ea_hdr;
|
||||
uint8_t arp_sha[ETH_ALEN];
|
||||
uint8_t arp_spa[4];
|
||||
uint8_t arp_tha[ETH_ALEN];
|
||||
uint8_t arp_tpa[4];
|
||||
} __attribute__((__packed__));
|
||||
#define arp_hrd ea_hdr.ar_hrd
|
||||
#define arp_pro ea_hdr.ar_pro
|
||||
#define arp_hln ea_hdr.ar_hln
|
||||
#define arp_pln ea_hdr.ar_pln
|
||||
#define arp_op ea_hdr.ar_op
|
||||
#endif
|
||||
|
||||
#endif
|
||||
121
src/event.c
Normal file
121
src/event.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
event.c -- event queue
|
||||
Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2002-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "event.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
avl_tree_t *event_tree;
|
||||
extern time_t now;
|
||||
|
||||
static int id;
|
||||
|
||||
static int event_compare(const event_t *a, const event_t *b) {
|
||||
if(a->time > b->time) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(a->time < b->time) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return a->id - b->id;
|
||||
}
|
||||
|
||||
void init_events(void) {
|
||||
event_tree = avl_alloc_tree((avl_compare_t) event_compare, (avl_action_t) free_event);
|
||||
}
|
||||
|
||||
void exit_events(void) {
|
||||
avl_delete_tree(event_tree);
|
||||
}
|
||||
|
||||
void expire_events(void) {
|
||||
avl_node_t *node;
|
||||
event_t *event;
|
||||
time_t diff;
|
||||
|
||||
/*
|
||||
* Make all events appear expired by subtracting the difference between
|
||||
* the expiration time of the last event and the current time.
|
||||
*/
|
||||
|
||||
if(!event_tree->tail) {
|
||||
return;
|
||||
}
|
||||
|
||||
event = event_tree->tail->data;
|
||||
|
||||
if(event->time <= now) {
|
||||
return;
|
||||
}
|
||||
|
||||
diff = event->time - now;
|
||||
|
||||
for(node = event_tree->head; node; node = node->next) {
|
||||
event = node->data;
|
||||
event->time -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
event_t *new_event(void) {
|
||||
return xmalloc_and_zero(sizeof(event_t));
|
||||
}
|
||||
|
||||
void free_event(event_t *event) {
|
||||
free(event);
|
||||
}
|
||||
|
||||
void event_add(event_t *event) {
|
||||
event->id = ++id;
|
||||
avl_insert(event_tree, event);
|
||||
}
|
||||
|
||||
void event_del(event_t *event) {
|
||||
avl_delete(event_tree, event);
|
||||
}
|
||||
|
||||
event_t *get_expired_event(void) {
|
||||
event_t *event;
|
||||
|
||||
if(event_tree->head) {
|
||||
event = event_tree->head->data;
|
||||
|
||||
if(event->time <= now) {
|
||||
avl_node_t *node = event_tree->head;
|
||||
avl_unlink_node(event_tree, node);
|
||||
free(node);
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
event_t *peek_next_event(void) {
|
||||
if(event_tree->head) {
|
||||
return event_tree->head->data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
47
src/event.h
Normal file
47
src/event.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef TINC_EVENT_H
|
||||
#define TINC_EVENT_H
|
||||
|
||||
/*
|
||||
event.h -- header for event.c
|
||||
Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2002-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "avl_tree.h"
|
||||
|
||||
extern avl_tree_t *event_tree;
|
||||
|
||||
typedef void (*event_handler_t)(void *);
|
||||
|
||||
typedef struct event {
|
||||
time_t time;
|
||||
int id;
|
||||
event_handler_t handler;
|
||||
void *data;
|
||||
} event_t;
|
||||
|
||||
extern void init_events(void);
|
||||
extern void exit_events(void);
|
||||
extern void expire_events(void);
|
||||
extern event_t *new_event(void) __attribute__((__malloc__));
|
||||
extern void free_event(event_t *event);
|
||||
extern void event_add(event_t *event);
|
||||
extern void event_del(event_t *event);
|
||||
extern event_t *get_expired_event(void);
|
||||
extern event_t *peek_next_event(void);
|
||||
|
||||
#endif
|
||||
108
src/fake-getaddrinfo.c
Normal file
108
src/fake-getaddrinfo.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
|
||||
* These functions are defined in rfc2133.
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For example, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "ipv4.h"
|
||||
#include "ipv6.h"
|
||||
#include "fake-getaddrinfo.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#if !HAVE_DECL_GAI_STRERROR
|
||||
char *gai_strerror(int ecode) {
|
||||
switch(ecode) {
|
||||
case EAI_NODATA:
|
||||
return "No address associated with hostname";
|
||||
|
||||
case EAI_MEMORY:
|
||||
return "Memory allocation failure";
|
||||
|
||||
case EAI_FAMILY:
|
||||
return "Address family not supported";
|
||||
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#if !HAVE_DECL_FREEADDRINFO
|
||||
void freeaddrinfo(struct addrinfo *ai) {
|
||||
struct addrinfo *next;
|
||||
|
||||
while(ai) {
|
||||
next = ai->ai_next;
|
||||
free(ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GETADDRINFO
|
||||
static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) {
|
||||
struct addrinfo *ai;
|
||||
|
||||
ai = xmalloc_and_zero(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
|
||||
|
||||
ai->ai_addr = (struct sockaddr *)(ai + 1);
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
ai->ai_addr->sa_family = ai->ai_family = AF_INET;
|
||||
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) {
|
||||
struct addrinfo *prev = NULL;
|
||||
struct hostent *hp;
|
||||
struct in_addr in = {0};
|
||||
int i;
|
||||
uint16_t port = 0;
|
||||
|
||||
if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC) {
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
if(servname) {
|
||||
port = htons(atoi(servname));
|
||||
}
|
||||
|
||||
if(hints && hints->ai_flags & AI_PASSIVE) {
|
||||
*res = malloc_ai(port, htonl(0x00000000));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!hostname) {
|
||||
*res = malloc_ai(port, htonl(0x7f000001));
|
||||
return 0;
|
||||
}
|
||||
|
||||
hp = gethostbyname(hostname);
|
||||
|
||||
if(!hp || !hp->h_addr_list || !hp->h_addr_list[0]) {
|
||||
return EAI_NODATA;
|
||||
}
|
||||
|
||||
for(i = 0; hp->h_addr_list[i]; i++) {
|
||||
*res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
|
||||
|
||||
if(prev) {
|
||||
prev->ai_next = *res;
|
||||
}
|
||||
|
||||
prev = *res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
57
src/fake-getaddrinfo.h
Normal file
57
src/fake-getaddrinfo.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef TINC_FAKE_GETADDRINFO_H
|
||||
#define TINC_FAKE_GETADDRINFO_H
|
||||
|
||||
#ifndef EAI_NODATA
|
||||
#define EAI_NODATA 1
|
||||
#endif
|
||||
|
||||
#ifndef EAI_MEMORY
|
||||
#define EAI_MEMORY 2
|
||||
#endif
|
||||
|
||||
#ifndef EAI_FAMILY
|
||||
#define EAI_FAMILY 3
|
||||
#endif
|
||||
|
||||
#ifndef AI_PASSIVE
|
||||
# define AI_PASSIVE 1
|
||||
# define AI_CANONNAME 2
|
||||
#endif
|
||||
|
||||
#ifndef NI_NUMERICHOST
|
||||
# define NI_NUMERICHOST 2
|
||||
# define NI_NAMEREQD 4
|
||||
# define NI_NUMERICSERV 8
|
||||
#endif
|
||||
|
||||
#ifndef AI_NUMERICHOST
|
||||
#define AI_NUMERICHOST 4
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ADDRINFO
|
||||
struct addrinfo {
|
||||
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
|
||||
int ai_family; /* PF_xxx */
|
||||
int ai_socktype; /* SOCK_xxx */
|
||||
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
|
||||
size_t ai_addrlen; /* length of ai_addr */
|
||||
char *ai_canonname; /* canonical name for hostname */
|
||||
struct sockaddr *ai_addr; /* binary address */
|
||||
struct addrinfo *ai_next; /* next structure in linked list */
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_ADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GETADDRINFO
|
||||
int getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GAI_STRERROR
|
||||
char *gai_strerror(int ecode);
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#if !HAVE_DECL_FREEADDRINFO
|
||||
void freeaddrinfo(struct addrinfo *ai);
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#endif
|
||||
64
src/fake-getnameinfo.c
Normal file
64
src/fake-getnameinfo.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file includes getnameinfo().
|
||||
* These functions are defined in rfc2133.
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For example, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "fake-getnameinfo.h"
|
||||
#include "fake-getaddrinfo.h"
|
||||
|
||||
#if !HAVE_DECL_GETNAMEINFO
|
||||
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||
struct hostent *hp;
|
||||
int len;
|
||||
|
||||
if(sa->sa_family != AF_INET) {
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
if(serv && servlen) {
|
||||
len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
|
||||
|
||||
if(len < 0 || len >= servlen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if(!host || !hostlen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(flags & NI_NUMERICHOST) {
|
||||
len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
|
||||
|
||||
if(len < 0 || len >= hostlen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
|
||||
|
||||
if(!hp || !hp->h_name || !hp->h_name[0]) {
|
||||
return EAI_NODATA;
|
||||
}
|
||||
|
||||
len = snprintf(host, hostlen, "%s", hp->h_name);
|
||||
|
||||
if(len < 0 || len >= hostlen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
16
src/fake-getnameinfo.h
Normal file
16
src/fake-getnameinfo.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef TINC_FAKE_GETNAMEINFO_H
|
||||
#define TINC_FAKE_GETNAMEINFO_H
|
||||
|
||||
#if !HAVE_DECL_GETNAMEINFO
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
|
||||
size_t hostlen, char *serv, size_t servlen, int flags);
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
# define NI_MAXSERV 32
|
||||
#endif /* !NI_MAXSERV */
|
||||
#ifndef NI_MAXHOST
|
||||
# define NI_MAXHOST 1025
|
||||
#endif /* !NI_MAXHOST */
|
||||
|
||||
#endif
|
||||
1051
src/getopt.c
Normal file
1051
src/getopt.c
Normal file
File diff suppressed because it is too large
Load diff
132
src/getopt.h
Normal file
132
src/getopt.h
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#ifndef TINC_GETOPT_H
|
||||
#define TINC_GETOPT_H
|
||||
|
||||
/* Declarations for getopt.
|
||||
Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
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, 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.
|
||||
*/
|
||||
|
||||
#ifdef cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns -1, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
extern int optopt;
|
||||
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option {
|
||||
#if defined (__STDC__) && __STDC__
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#if defined (__STDC__) && __STDC__
|
||||
#ifdef __GNU_LIBRARY__
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt(int argc, char *const *argv, const char *shortopts);
|
||||
#else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt();
|
||||
#endif /* __GNU_LIBRARY__ */
|
||||
extern int getopt_long(int argc, char *const *argv, const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
extern int getopt_long_only(int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal(int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind,
|
||||
int long_only);
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt();
|
||||
extern int getopt_long();
|
||||
extern int getopt_long_only();
|
||||
|
||||
extern int _getopt_internal();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
195
src/getopt1.c
Normal file
195
src/getopt1.c
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/* getopt_long and getopt_long_only entry points for GNU getopt.
|
||||
Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
|
||||
|
||||
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, 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../config.h"
|
||||
#endif
|
||||
|
||||
#include "getopt.h"
|
||||
|
||||
#if !defined (__STDC__) || !__STDC__
|
||||
/* This is a separate conditional since some stdc systems
|
||||
reject `defined (const)'. */
|
||||
#ifndef const
|
||||
#define const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Comment out all this code if we are using the GNU C Library, and are not
|
||||
actually compiling the library itself. This code is part of the GNU C
|
||||
Library, but also included in many other GNU distributions. Compiling
|
||||
and linking in this code is a waste when using the GNU C library
|
||||
(especially if it is a shared library). Rather than having every GNU
|
||||
program understand `configure --with-gnu-libc' and omit the object files,
|
||||
it is simpler to just do this in the source for each such file. */
|
||||
|
||||
#define GETOPT_INTERFACE_VERSION 2
|
||||
#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
|
||||
#include <gnu-versions.h>
|
||||
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
|
||||
#define ELIDE_CODE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ELIDE_CODE
|
||||
|
||||
|
||||
/* This needs to come after some library #include
|
||||
to get __GNU_LIBRARY__ defined. */
|
||||
#ifdef __GNU_LIBRARY__
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
int
|
||||
getopt_long(argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal(argc, argv, options, long_options, opt_index, 0);
|
||||
}
|
||||
|
||||
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
|
||||
If an option that starts with '-' (not '--') doesn't match a long option,
|
||||
but does match a short option, it is parsed as a short option
|
||||
instead. */
|
||||
|
||||
int
|
||||
getopt_long_only(argc, argv, options, long_options, opt_index)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *options;
|
||||
const struct option *long_options;
|
||||
int *opt_index;
|
||||
{
|
||||
return _getopt_internal(argc, argv, options, long_options, opt_index, 1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* Not ELIDE_CODE. */
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
|
||||
while(1) {
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"add", 1, 0, 0},
|
||||
{"append", 0, 0, 0},
|
||||
{"delete", 1, 0, 0},
|
||||
{"verbose", 0, 0, 0},
|
||||
{"create", 0, 0, 0},
|
||||
{"file", 1, 0, 0},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "abc:d:0123456789",
|
||||
long_options, &option_index);
|
||||
|
||||
if(c == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch(c) {
|
||||
case 0:
|
||||
printf("option %s", long_options[option_index].name);
|
||||
|
||||
if(optarg) {
|
||||
printf(" with arg %s", optarg);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
break;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if(digit_optind != 0 && digit_optind != this_option_optind) {
|
||||
printf("digits occur in two different argv-elements.\n");
|
||||
}
|
||||
|
||||
digit_optind = this_option_optind;
|
||||
printf("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf("option c with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
printf("option d with value `%s'\n", optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("?? getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if(optind < argc) {
|
||||
printf("non-option ARGV-elements: ");
|
||||
|
||||
while(optind < argc) {
|
||||
printf("%s ", argv[optind++]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
||||
390
src/graph.c
Normal file
390
src/graph.c
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
graph.c -- graph algorithms
|
||||
Copyright (C) 2001-2014 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/* We need to generate two trees from the graph:
|
||||
|
||||
1. A minimum spanning tree for broadcasts,
|
||||
2. A single-source shortest path tree for unicasts.
|
||||
|
||||
Actually, the first one alone would suffice but would make unicast packets
|
||||
take longer routes than necessary.
|
||||
|
||||
For the MST algorithm we can choose from Prim's or Kruskal's. I personally
|
||||
favour Kruskal's, because we make an extra AVL tree of edges sorted on
|
||||
weights (metric). That tree only has to be updated when an edge is added or
|
||||
removed, and during the MST algorithm we just have go linearly through that
|
||||
tree, adding safe edges until #edges = #nodes - 1. The implementation here
|
||||
however is not so fast, because I tried to avoid having to make a forest and
|
||||
merge trees.
|
||||
|
||||
For the SSSP algorithm Dijkstra's seems to be a nice choice. Currently a
|
||||
simple breadth-first search is presented here.
|
||||
|
||||
The SSSP algorithm will also be used to determine whether nodes are directly,
|
||||
indirectly or not reachable from the source. It will also set the correct
|
||||
destination address and port of a node if possible.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
#include "device.h"
|
||||
#include "edge.h"
|
||||
#include "graph.h"
|
||||
#include "logger.h"
|
||||
#include "netutl.h"
|
||||
#include "node.h"
|
||||
#include "process.h"
|
||||
#include "protocol.h"
|
||||
#include "subnet.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static bool graph_changed = true;
|
||||
|
||||
/* Implementation of Kruskal's algorithm.
|
||||
Running time: O(EN)
|
||||
Please note that sorting on weight is already done by add_edge().
|
||||
*/
|
||||
|
||||
static void mst_kruskal(void) {
|
||||
avl_node_t *node, *next;
|
||||
edge_t *e;
|
||||
node_t *n;
|
||||
connection_t *c;
|
||||
int nodes = 0;
|
||||
int safe_edges = 0;
|
||||
bool skipped;
|
||||
|
||||
/* Clear MST status on connections */
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
c->status.mst = false;
|
||||
}
|
||||
|
||||
/* Do we have something to do at all? */
|
||||
|
||||
if(!edge_weight_tree->head) {
|
||||
return;
|
||||
}
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:");
|
||||
|
||||
/* Clear visited status on nodes */
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
n->status.visited = false;
|
||||
nodes++;
|
||||
}
|
||||
|
||||
/* Starting point */
|
||||
|
||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
||||
e = node->data;
|
||||
|
||||
if(e->from->status.reachable) {
|
||||
e->from->status.visited = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add safe edges */
|
||||
|
||||
for(skipped = false, node = edge_weight_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
e = node->data;
|
||||
|
||||
if(!e->reverse || e->from->status.visited == e->to->status.visited) {
|
||||
skipped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
e->from->status.visited = true;
|
||||
e->to->status.visited = true;
|
||||
|
||||
if(e->connection) {
|
||||
e->connection->status.mst = true;
|
||||
}
|
||||
|
||||
if(e->reverse->connection) {
|
||||
e->reverse->connection->status.mst = true;
|
||||
}
|
||||
|
||||
safe_edges++;
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
|
||||
e->to->name, e->weight);
|
||||
|
||||
if(skipped) {
|
||||
skipped = false;
|
||||
next = edge_weight_tree->head;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes,
|
||||
safe_edges);
|
||||
}
|
||||
|
||||
/* Implementation of a simple breadth-first search algorithm.
|
||||
Running time: O(E)
|
||||
*/
|
||||
|
||||
static void sssp_bfs(void) {
|
||||
avl_node_t *node, *next, *to;
|
||||
edge_t *e;
|
||||
node_t *n;
|
||||
list_t *todo_list;
|
||||
list_node_t *from, *todonext;
|
||||
bool indirect;
|
||||
char *name;
|
||||
char *address, *port;
|
||||
char *envp[8] = {NULL};
|
||||
int i;
|
||||
|
||||
todo_list = list_alloc(NULL);
|
||||
|
||||
/* Clear visited status on nodes */
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
n->status.visited = false;
|
||||
n->status.indirect = true;
|
||||
}
|
||||
|
||||
/* Begin with myself */
|
||||
|
||||
myself->status.visited = true;
|
||||
myself->status.indirect = false;
|
||||
myself->nexthop = myself;
|
||||
myself->prevedge = NULL;
|
||||
myself->via = myself;
|
||||
list_insert_head(todo_list, myself);
|
||||
|
||||
/* Loop while todo_list is filled */
|
||||
|
||||
for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */
|
||||
n = from->data;
|
||||
|
||||
for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */
|
||||
e = to->data;
|
||||
|
||||
if(!e->reverse) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Situation:
|
||||
|
||||
/
|
||||
/
|
||||
----->(n)---e-->(e->to)
|
||||
\
|
||||
\
|
||||
|
||||
Where e is an edge, (n) and (e->to) are nodes.
|
||||
n->address is set to the e->address of the edge left of n to n.
|
||||
We are currently examining the edge e right of n from n:
|
||||
|
||||
- If edge e provides for better reachability of e->to, update
|
||||
e->to and (re)add it to the todo_list to (re)examine the reachability
|
||||
of nodes behind it.
|
||||
*/
|
||||
|
||||
indirect = n->status.indirect || e->options & OPTION_INDIRECT;
|
||||
|
||||
if(e->to->status.visited
|
||||
&& (!e->to->status.indirect || indirect)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only update nexthop the first time we visit this node.
|
||||
|
||||
if(!e->to->status.visited) {
|
||||
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
|
||||
}
|
||||
|
||||
e->to->status.visited = true;
|
||||
e->to->status.indirect = indirect;
|
||||
e->to->prevedge = e;
|
||||
e->to->via = indirect ? n->via : e->to;
|
||||
e->to->options = e->options;
|
||||
|
||||
if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN) {
|
||||
update_node_udp(e->to, &e->address);
|
||||
}
|
||||
|
||||
list_insert_tail(todo_list, e->to);
|
||||
}
|
||||
|
||||
todonext = from->next;
|
||||
list_delete_node(todo_list, from);
|
||||
}
|
||||
|
||||
list_free(todo_list);
|
||||
|
||||
/* Check reachability status. */
|
||||
|
||||
for(node = node_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
n = node->data;
|
||||
|
||||
if(n->status.visited != n->status.reachable) {
|
||||
n->status.reachable = !n->status.reachable;
|
||||
|
||||
if(n->status.reachable) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable",
|
||||
n->name, n->hostname);
|
||||
} else {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable",
|
||||
n->name, n->hostname);
|
||||
}
|
||||
|
||||
/* TODO: only clear status.validkey if node is unreachable? */
|
||||
|
||||
n->status.validkey = false;
|
||||
n->last_req_key = 0;
|
||||
|
||||
n->maxmtu = MTU;
|
||||
n->minmtu = 0;
|
||||
n->mtuprobes = 0;
|
||||
|
||||
if(n->mtuevent) {
|
||||
event_del(n->mtuevent);
|
||||
n->mtuevent = NULL;
|
||||
}
|
||||
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? netname : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? device : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? iface : "");
|
||||
xasprintf(&envp[3], "NODE=%s", n->name);
|
||||
sockaddr2str(&n->address, &address, &port);
|
||||
xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
|
||||
xasprintf(&envp[5], "REMOTEPORT=%s", port);
|
||||
xasprintf(&envp[6], "NAME=%s", myself->name);
|
||||
|
||||
execute_script(n->status.reachable ? "host-up" : "host-down", envp);
|
||||
|
||||
xasprintf(&name,
|
||||
n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
|
||||
n->name);
|
||||
execute_script(name, envp);
|
||||
|
||||
free(name);
|
||||
free(address);
|
||||
free(port);
|
||||
|
||||
for(i = 0; i < 7; i++) {
|
||||
free(envp[i]);
|
||||
}
|
||||
|
||||
subnet_update(n, NULL, n->status.reachable);
|
||||
|
||||
if(!n->status.reachable) {
|
||||
update_node_udp(n, NULL);
|
||||
memset(&n->status, 0, sizeof(n->status));
|
||||
n->options = 0;
|
||||
} else if(n->connection) {
|
||||
send_ans_key(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void graph(void) {
|
||||
subnet_cache_flush();
|
||||
sssp_bfs();
|
||||
mst_kruskal();
|
||||
graph_changed = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Dump nodes and edges to a graphviz file.
|
||||
|
||||
The file can be converted to an image with
|
||||
dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true
|
||||
*/
|
||||
|
||||
void dump_graph(void) {
|
||||
avl_node_t *node;
|
||||
node_t *n;
|
||||
edge_t *e;
|
||||
char *filename = NULL, *tmpname = NULL;
|
||||
FILE *file, *pipe = NULL;
|
||||
|
||||
if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
graph_changed = false;
|
||||
|
||||
ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph");
|
||||
|
||||
if(filename[0] == '|') {
|
||||
file = pipe = popen(filename + 1, "w");
|
||||
} else {
|
||||
xasprintf(&tmpname, "%s.new", filename);
|
||||
file = fopen(tmpname, "w");
|
||||
}
|
||||
|
||||
if(!file) {
|
||||
logger(LOG_ERR, "Unable to open graph dump file %s: %s", filename, strerror(errno));
|
||||
free(filename);
|
||||
free(tmpname);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(file, "digraph {\n");
|
||||
|
||||
/* dump all nodes first */
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
fprintf(file, " \"%s\" [label = \"%s\"];\n", n->name, n->name);
|
||||
}
|
||||
|
||||
/* now dump all edges */
|
||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
||||
e = node->data;
|
||||
fprintf(file, " \"%s\" -> \"%s\";\n", e->from->name, e->to->name);
|
||||
}
|
||||
|
||||
fprintf(file, "}\n");
|
||||
|
||||
if(pipe) {
|
||||
pclose(pipe);
|
||||
} else {
|
||||
fclose(file);
|
||||
#ifdef HAVE_MINGW
|
||||
unlink(filename);
|
||||
#endif
|
||||
|
||||
if(rename(tmpname, filename)) {
|
||||
logger(LOG_ERR, "Could not rename %s to %s: %s\n", tmpname, filename, strerror(errno));
|
||||
}
|
||||
|
||||
free(tmpname);
|
||||
}
|
||||
|
||||
free(filename);
|
||||
}
|
||||
27
src/graph.h
Normal file
27
src/graph.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef TINC_GRAPH_H
|
||||
#define TINC_GRAPH_H
|
||||
|
||||
/*
|
||||
graph.h -- header for graph.c
|
||||
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
extern void graph(void);
|
||||
extern void dump_graph(void);
|
||||
|
||||
#endif
|
||||
214
src/have.h
Normal file
214
src/have.h
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
#ifndef TINC_HAVE_H
|
||||
#define TINC_HAVE_H
|
||||
|
||||
/*
|
||||
have.h -- include headers which are known to exist
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2003-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#ifdef WITH_WINDOWS2000
|
||||
#define WINVER Windows2000
|
||||
#else
|
||||
#define WINVER WindowsXP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#include <w32api.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
/* Include system specific headers */
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_FILE_H
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DIRENT_H
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
/* SunOS really wants sys/socket.h BEFORE net/if.h,
|
||||
and FreeBSD wants these lines below the rest. */
|
||||
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_TYPES_H
|
||||
#include <net/if_types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_TUN_H
|
||||
#include <net/if_tun.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_TUN_IF_TUN_H
|
||||
#include <net/tun/if_tun.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_TAP_H
|
||||
#include <net/if_tap.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_TAP_IF_TAP_H
|
||||
#include <net/tap/if_tap.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_SYSTM_H
|
||||
#include <netinet/in_systm.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IP_H
|
||||
#include <netinet/ip.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN6_H
|
||||
#include <netinet/in6.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IP6_H
|
||||
#include <netinet/ip6.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_ETHERNET_H
|
||||
#include <net/ethernet.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_ARP_H
|
||||
#include <net/if_arp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IP_ICMP_H
|
||||
#include <netinet/ip_icmp.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_ICMP6_H
|
||||
#include <netinet/icmp6.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IF_ETHER_H
|
||||
#include <netinet/if_ether.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_NAMESER_H
|
||||
#include <arpa/nameser.h>
|
||||
#ifdef STATUS
|
||||
#undef STATUS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RESOLV_H
|
||||
#include <resolv.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_IF_TUN_H
|
||||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
149
src/ipv4.h
Normal file
149
src/ipv4.h
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
#ifndef TINC_IPV4_H
|
||||
#define TINC_IPV4_H
|
||||
|
||||
/*
|
||||
ipv4.h -- missing IPv4 related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef AF_INET
|
||||
#define AF_INET 2
|
||||
#endif
|
||||
|
||||
#ifndef IPPROTO_ICMP
|
||||
#define IPPROTO_ICMP 1
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_DEST_UNREACH
|
||||
#define ICMP_DEST_UNREACH 3
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_FRAG_NEEDED
|
||||
#define ICMP_FRAG_NEEDED 4
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_NET_UNKNOWN
|
||||
#define ICMP_NET_UNKNOWN 6
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_TIME_EXCEEDED
|
||||
#define ICMP_TIME_EXCEEDED 11
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_EXC_TTL
|
||||
#define ICMP_EXC_TTL 0
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_NET_UNREACH
|
||||
#define ICMP_NET_UNREACH 0
|
||||
#endif
|
||||
|
||||
#ifndef ICMP_NET_ANO
|
||||
#define ICMP_NET_ANO 9
|
||||
#endif
|
||||
|
||||
#ifndef IP_MSS
|
||||
#define IP_MSS 576
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_IP
|
||||
struct ip {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
unsigned int ip_hl: 4;
|
||||
unsigned int ip_v: 4;
|
||||
#else
|
||||
unsigned int ip_v: 4;
|
||||
unsigned int ip_hl: 4;
|
||||
#endif
|
||||
uint8_t ip_tos;
|
||||
uint16_t ip_len;
|
||||
uint16_t ip_id;
|
||||
uint16_t ip_off;
|
||||
#define IP_RF 0x8000
|
||||
#define IP_DF 0x4000
|
||||
#define IP_MF 0x2000
|
||||
uint8_t ip_ttl;
|
||||
uint8_t ip_p;
|
||||
uint16_t ip_sum;
|
||||
struct in_addr ip_src, ip_dst;
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#ifndef IP_OFFMASK
|
||||
#define IP_OFFMASK 0x1fff
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ICMP
|
||||
struct icmp {
|
||||
uint8_t icmp_type;
|
||||
uint8_t icmp_code;
|
||||
uint16_t icmp_cksum;
|
||||
union {
|
||||
uint8_t ih_pptr;
|
||||
struct in_addr ih_gwaddr;
|
||||
struct ih_idseq {
|
||||
uint16_t icd_id;
|
||||
uint16_t icd_seq;
|
||||
} ih_idseq;
|
||||
uint32_t ih_void;
|
||||
|
||||
|
||||
struct ih_pmtu {
|
||||
uint16_t ipm_void;
|
||||
uint16_t ipm_nextmtu;
|
||||
} ih_pmtu;
|
||||
|
||||
struct ih_rtradv {
|
||||
uint8_t irt_num_addrs;
|
||||
uint8_t irt_wpa;
|
||||
uint16_t irt_lifetime;
|
||||
} ih_rtradv;
|
||||
} icmp_hun;
|
||||
#define icmp_pptr icmp_hun.ih_pptr
|
||||
#define icmp_gwaddr icmp_hun.ih_gwaddr
|
||||
#define icmp_id icmp_hun.ih_idseq.icd_id
|
||||
#define icmp_seq icmp_hun.ih_idseq.icd_seq
|
||||
#define icmp_void icmp_hun.ih_void
|
||||
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
|
||||
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
|
||||
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
|
||||
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
|
||||
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
|
||||
union {
|
||||
struct {
|
||||
uint32_t its_otime;
|
||||
uint32_t its_rtime;
|
||||
uint32_t its_ttime;
|
||||
} id_ts;
|
||||
struct {
|
||||
struct ip idi_ip;
|
||||
} id_ip;
|
||||
uint32_t id_mask;
|
||||
uint8_t id_data[1];
|
||||
} icmp_dun;
|
||||
#define icmp_otime icmp_dun.id_ts.its_otime
|
||||
#define icmp_rtime icmp_dun.id_ts.its_rtime
|
||||
#define icmp_ttime icmp_dun.id_ts.its_ttime
|
||||
#define icmp_ip icmp_dun.id_ip.idi_ip
|
||||
#define icmp_radv icmp_dun.id_radv
|
||||
#define icmp_mask icmp_dun.id_mask
|
||||
#define icmp_data icmp_dun.id_data
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
130
src/ipv6.h
Normal file
130
src/ipv6.h
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
#ifndef TINC_IPV6_H
|
||||
#define TINC_IPV6_H
|
||||
|
||||
/*
|
||||
ipv6.h -- missing IPv6 related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef AF_INET6
|
||||
#define AF_INET6 10
|
||||
#endif
|
||||
|
||||
#ifndef IPPROTO_ICMPV6
|
||||
#define IPPROTO_ICMPV6 58
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_IN6_ADDR
|
||||
struct in6_addr {
|
||||
union {
|
||||
uint8_t u6_addr8[16];
|
||||
uint16_t u6_addr16[8];
|
||||
uint32_t u6_addr32[4];
|
||||
} in6_u;
|
||||
} __attribute__((__packed__));
|
||||
#define s6_addr in6_u.u6_addr8
|
||||
#define s6_addr16 in6_u.u6_addr16
|
||||
#define s6_addr32 in6_u.u6_addr32
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_SOCKADDR_IN6
|
||||
struct sockaddr_in6 {
|
||||
uint16_t sin6_family;
|
||||
uint16_t sin6_port;
|
||||
uint32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
uint32_t sin6_scope_id;
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#ifndef IN6_IS_ADDR_V4MAPPED
|
||||
#define IN6_IS_ADDR_V4MAPPED(a) \
|
||||
((((const uint32_t *) (a))[0] == 0) \
|
||||
&& (((const uint32_t *) (a))[1] == 0) \
|
||||
&& (((const uint32_t *) (a))[2] == htonl (0xffff)))
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_IP6_HDR
|
||||
struct ip6_hdr {
|
||||
union {
|
||||
struct ip6_hdrctl {
|
||||
uint32_t ip6_un1_flow;
|
||||
uint16_t ip6_un1_plen;
|
||||
uint8_t ip6_un1_nxt;
|
||||
uint8_t ip6_un1_hlim;
|
||||
} ip6_un1;
|
||||
uint8_t ip6_un2_vfc;
|
||||
} ip6_ctlun;
|
||||
struct in6_addr ip6_src;
|
||||
struct in6_addr ip6_dst;
|
||||
} __attribute__((__packed__));
|
||||
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
|
||||
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
|
||||
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
|
||||
#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
|
||||
#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
|
||||
#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ICMP6_HDR
|
||||
struct icmp6_hdr {
|
||||
uint8_t icmp6_type;
|
||||
uint8_t icmp6_code;
|
||||
uint16_t icmp6_cksum;
|
||||
union {
|
||||
uint32_t icmp6_un_data32[1];
|
||||
uint16_t icmp6_un_data16[2];
|
||||
uint8_t icmp6_un_data8[4];
|
||||
} icmp6_dataun;
|
||||
} __attribute__((__packed__));
|
||||
#define ICMP6_DST_UNREACH_NOROUTE 0
|
||||
#define ICMP6_DST_UNREACH 1
|
||||
#define ICMP6_PACKET_TOO_BIG 2
|
||||
#define ICMP6_TIME_EXCEEDED 3
|
||||
#define ICMP6_DST_UNREACH_ADMIN 1
|
||||
#define ICMP6_DST_UNREACH_ADDR 3
|
||||
#define ICMP6_TIME_EXCEED_TRANSIT 0
|
||||
#define ND_NEIGHBOR_SOLICIT 135
|
||||
#define ND_NEIGHBOR_ADVERT 136
|
||||
#define icmp6_data32 icmp6_dataun.icmp6_un_data32
|
||||
#define icmp6_data16 icmp6_dataun.icmp6_un_data16
|
||||
#define icmp6_data8 icmp6_dataun.icmp6_un_data8
|
||||
#define icmp6_mtu icmp6_data32[0]
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ND_NEIGHBOR_SOLICIT
|
||||
struct nd_neighbor_solicit {
|
||||
struct icmp6_hdr nd_ns_hdr;
|
||||
struct in6_addr nd_ns_target;
|
||||
} __attribute__((__packed__));
|
||||
#define ND_OPT_SOURCE_LINKADDR 1
|
||||
#define ND_OPT_TARGET_LINKADDR 2
|
||||
#define nd_ns_type nd_ns_hdr.icmp6_type
|
||||
#define nd_ns_code nd_ns_hdr.icmp6_code
|
||||
#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
|
||||
#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ND_OPT_HDR
|
||||
struct nd_opt_hdr {
|
||||
uint8_t nd_opt_type;
|
||||
uint8_t nd_opt_len;
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
228
src/linux/device.c
Normal file
228
src/linux/device.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
device.c -- Interaction with Linux tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include <linux/if_tun.h>
|
||||
#define DEFAULT_DEVICE "/dev/net/tun"
|
||||
|
||||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../net.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
typedef enum device_type_t {
|
||||
DEVICE_TYPE_TUN,
|
||||
DEVICE_TYPE_TAP,
|
||||
} device_type_t;
|
||||
|
||||
int device_fd = -1;
|
||||
static device_type_t device_type;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static char *type = NULL;
|
||||
static char ifrname[IFNAMSIZ];
|
||||
static const char *device_info;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
struct ifreq ifr;
|
||||
bool t1q = false;
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
device = xstrdup(DEFAULT_DEVICE);
|
||||
}
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
if(netname != NULL) {
|
||||
iface = xstrdup(netname);
|
||||
}
|
||||
|
||||
device_fd = open(device, O_RDWR | O_NONBLOCK);
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
get_config_string(lookup_config(config_tree, "DeviceType"), &type);
|
||||
|
||||
if(type && strcasecmp(type, "tun") && strcasecmp(type, "tap")) {
|
||||
logger(LOG_ERR, "Unknown device type %s!", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((type && !strcasecmp(type, "tun")) || (!type && routing_mode == RMODE_ROUTER)) {
|
||||
ifr.ifr_flags = IFF_TUN;
|
||||
device_type = DEVICE_TYPE_TUN;
|
||||
device_info = "Linux tun/tap device (tun mode)";
|
||||
} else {
|
||||
if(routing_mode == RMODE_ROUTER) {
|
||||
overwrite_mac = true;
|
||||
}
|
||||
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
device_info = "Linux tun/tap device (tap mode)";
|
||||
}
|
||||
|
||||
#ifdef IFF_ONE_QUEUE
|
||||
|
||||
/* Set IFF_ONE_QUEUE flag... */
|
||||
if(get_config_bool(lookup_config(config_tree, "IffOneQueue"), &t1q) && t1q) {
|
||||
ifr.ifr_flags |= IFF_ONE_QUEUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(iface) {
|
||||
strncpy(ifr.ifr_name, iface, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = 0;
|
||||
}
|
||||
|
||||
if(!ioctl(device_fd, TUNSETIFF, &ifr)) {
|
||||
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
|
||||
ifrname[IFNAMSIZ - 1] = 0;
|
||||
free(iface);
|
||||
iface = xstrdup(ifrname);
|
||||
} else if(errno == EPERM || errno == EBUSY) {
|
||||
logger(LOG_ERR, "Error while trying to configure %s: %s", device, strerror(errno));
|
||||
return false;
|
||||
} else if(!ioctl(device_fd, (('T' << 8) | 202), &ifr)) {
|
||||
logger(LOG_WARNING, "Old ioctl() request was needed for %s", device);
|
||||
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
|
||||
ifrname[IFNAMSIZ - 1] = 0;
|
||||
free(iface);
|
||||
iface = xstrdup(ifrname);
|
||||
} else {
|
||||
logger(LOG_ERR, "%s is not a TUN/TAP device", device);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(overwrite_mac && !ioctl(device_fd, SIOCGIFHWADDR, &ifr)) {
|
||||
memcpy(mymac.x, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
}
|
||||
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
|
||||
free(type);
|
||||
free(device);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin;
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
lenin = read(device_fd, packet->data + 10, MTU - 10);
|
||||
|
||||
if(lenin <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s",
|
||||
device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = lenin + 10;
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
lenin = read(device_fd, packet->data, MTU);
|
||||
|
||||
if(lenin <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s",
|
||||
device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->len = lenin;
|
||||
break;
|
||||
}
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
packet->data[10] = packet->data[11] = 0;
|
||||
|
||||
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
178
src/list.c
Normal file
178
src/list.c
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
list.c -- functions to deal with double linked lists
|
||||
Copyright (C) 2000-2005 Ivo Timmermans
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "list.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
list_t *list_alloc(list_action_t delete) {
|
||||
list_t *list;
|
||||
|
||||
list = xmalloc_and_zero(sizeof(list_t));
|
||||
list->delete = delete;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void list_free(list_t *list) {
|
||||
free(list);
|
||||
}
|
||||
|
||||
list_node_t *list_alloc_node(void) {
|
||||
return xmalloc_and_zero(sizeof(list_node_t));
|
||||
}
|
||||
|
||||
void list_free_node(list_t *list, list_node_t *node) {
|
||||
if(node->data && list->delete) {
|
||||
list->delete(node->data);
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
list_node_t *list_insert_head(list_t *list, void *data) {
|
||||
list_node_t *node;
|
||||
|
||||
node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->prev = NULL;
|
||||
node->next = list->head;
|
||||
list->head = node;
|
||||
|
||||
if(node->next) {
|
||||
node->next->prev = node;
|
||||
} else {
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
list->count++;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
list_node_t *list_insert_tail(list_t *list, void *data) {
|
||||
list_node_t *node;
|
||||
|
||||
node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->next = NULL;
|
||||
node->prev = list->tail;
|
||||
list->tail = node;
|
||||
|
||||
if(node->prev) {
|
||||
node->prev->next = node;
|
||||
} else {
|
||||
list->head = node;
|
||||
}
|
||||
|
||||
list->count++;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void list_unlink_node(list_t *list, list_node_t *node) {
|
||||
if(node->prev) {
|
||||
node->prev->next = node->next;
|
||||
} else {
|
||||
list->head = node->next;
|
||||
}
|
||||
|
||||
if(node->next) {
|
||||
node->next->prev = node->prev;
|
||||
} else {
|
||||
list->tail = node->prev;
|
||||
}
|
||||
|
||||
list->count--;
|
||||
}
|
||||
|
||||
void list_delete_node(list_t *list, list_node_t *node) {
|
||||
list_unlink_node(list, node);
|
||||
list_free_node(list, node);
|
||||
}
|
||||
|
||||
void list_delete_head(list_t *list) {
|
||||
list_delete_node(list, list->head);
|
||||
}
|
||||
|
||||
void list_delete_tail(list_t *list) {
|
||||
list_delete_node(list, list->tail);
|
||||
}
|
||||
|
||||
/* Head/tail lookup */
|
||||
|
||||
void *list_get_head(list_t *list) {
|
||||
if(list->head) {
|
||||
return list->head->data;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void *list_get_tail(list_t *list) {
|
||||
if(list->tail) {
|
||||
return list->tail->data;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fast list deletion */
|
||||
|
||||
void list_delete_list(list_t *list) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
list_free_node(list, node);
|
||||
}
|
||||
|
||||
list_free(list);
|
||||
}
|
||||
|
||||
/* Traversing */
|
||||
|
||||
void list_foreach_node(list_t *list, list_action_node_t action) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
action(node);
|
||||
}
|
||||
}
|
||||
|
||||
void list_foreach(list_t *list, list_action_t action) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
|
||||
if(node->data) {
|
||||
action(node->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
src/list.h
Normal file
78
src/list.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef TINC_LIST_H
|
||||
#define TINC_LIST_H
|
||||
|
||||
/*
|
||||
list.h -- header file for list.c
|
||||
Copyright (C) 2000-2005 Ivo Timmermans
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
typedef struct list_node_t {
|
||||
struct list_node_t *prev;
|
||||
struct list_node_t *next;
|
||||
|
||||
/* Payload */
|
||||
|
||||
void *data;
|
||||
} list_node_t;
|
||||
|
||||
typedef void (*list_action_t)(const void *);
|
||||
typedef void (*list_action_node_t)(const list_node_t *);
|
||||
|
||||
typedef struct list_t {
|
||||
list_node_t *head;
|
||||
list_node_t *tail;
|
||||
int count;
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
list_action_t delete;
|
||||
} list_t;
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
extern list_t *list_alloc(list_action_t) __attribute__((__malloc__));
|
||||
extern void list_free(list_t *list);
|
||||
extern list_node_t *list_alloc_node(void);
|
||||
extern void list_free_node(list_t *list, list_node_t *node);
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
extern list_node_t *list_insert_head(list_t *list, void *data);
|
||||
extern list_node_t *list_insert_tail(list_t *list, void *data);
|
||||
|
||||
extern void list_unlink_node(list_t *list, list_node_t *node);
|
||||
extern void list_delete_node(list_t *list, list_node_t *node);
|
||||
|
||||
extern void list_delete_head(list_t *list);
|
||||
extern void list_delete_tail(list_t *list);
|
||||
|
||||
/* Head/tail lookup */
|
||||
|
||||
extern void *list_get_head(list_t *list);
|
||||
extern void *list_get_tail(list_t *list);
|
||||
|
||||
/* Fast list deletion */
|
||||
|
||||
extern void list_delete_list(list_t *list);
|
||||
|
||||
/* Traversing */
|
||||
|
||||
extern void list_foreach(list_t *list, list_action_t action);
|
||||
extern void list_foreach_node(list_t *list, list_action_node_t action);
|
||||
|
||||
#endif
|
||||
171
src/logger.c
Normal file
171
src/logger.c
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
logger.c -- logging code
|
||||
Copyright (C) 2004-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2004-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "logger.h"
|
||||
|
||||
debug_t debug_level = DEBUG_NOTHING;
|
||||
static logmode_t logmode = LOGMODE_STDERR;
|
||||
static pid_t logpid;
|
||||
extern char *logfilename;
|
||||
static FILE *logfile = NULL;
|
||||
#ifdef HAVE_MINGW
|
||||
static HANDLE loghandle = NULL;
|
||||
#endif
|
||||
static const char *logident = NULL;
|
||||
|
||||
void openlogger(const char *ident, logmode_t mode) {
|
||||
logident = ident;
|
||||
logmode = mode;
|
||||
|
||||
switch(mode) {
|
||||
case LOGMODE_STDERR:
|
||||
logpid = getpid();
|
||||
break;
|
||||
|
||||
case LOGMODE_FILE:
|
||||
logpid = getpid();
|
||||
logfile = fopen(logfilename, "a");
|
||||
|
||||
if(!logfile) {
|
||||
fprintf(stderr, "Could not open log file %s: %s\n", logfilename, strerror(errno));
|
||||
logmode = LOGMODE_NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LOGMODE_SYSLOG:
|
||||
#ifdef HAVE_MINGW
|
||||
loghandle = RegisterEventSource(NULL, logident);
|
||||
|
||||
if(!loghandle) {
|
||||
fprintf(stderr, "Could not open log handle!");
|
||||
logmode = LOGMODE_NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
#else
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
openlog(logident, LOG_CONS | LOG_PID, LOG_DAEMON);
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
case LOGMODE_NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void reopenlogger() {
|
||||
if(logmode != LOGMODE_FILE) {
|
||||
return;
|
||||
}
|
||||
|
||||
fflush(logfile);
|
||||
FILE *newfile = fopen(logfilename, "a");
|
||||
|
||||
if(!newfile) {
|
||||
logger(LOG_ERR, "Unable to reopen log file %s: %s", logfilename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
fclose(logfile);
|
||||
logfile = newfile;
|
||||
}
|
||||
|
||||
void logger(int priority, const char *format, ...) {
|
||||
va_list ap;
|
||||
char timestr[32] = "";
|
||||
time_t now;
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
switch(logmode) {
|
||||
case LOGMODE_STDERR:
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
break;
|
||||
|
||||
case LOGMODE_FILE:
|
||||
now = time(NULL);
|
||||
strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&now));
|
||||
fprintf(logfile, "%s %s[%ld]: ", timestr, logident, (long)logpid);
|
||||
vfprintf(logfile, format, ap);
|
||||
fprintf(logfile, "\n");
|
||||
fflush(logfile);
|
||||
break;
|
||||
|
||||
case LOGMODE_SYSLOG:
|
||||
#ifdef HAVE_MINGW
|
||||
{
|
||||
char message[4096];
|
||||
const char *messages[] = {message};
|
||||
vsnprintf(message, sizeof(message), format, ap);
|
||||
message[sizeof(message) - 1] = 0;
|
||||
ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#ifdef HAVE_VSYSLOG
|
||||
vsyslog(priority, format, ap);
|
||||
#else
|
||||
{
|
||||
char message[4096];
|
||||
vsnprintf(message, sizeof(message), format, ap);
|
||||
syslog(priority, "%s", message);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
case LOGMODE_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void closelogger(void) {
|
||||
switch(logmode) {
|
||||
case LOGMODE_FILE:
|
||||
fclose(logfile);
|
||||
break;
|
||||
|
||||
case LOGMODE_SYSLOG:
|
||||
#ifdef HAVE_MINGW
|
||||
DeregisterEventSource(loghandle);
|
||||
break;
|
||||
#else
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
closelog();
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
case LOGMODE_NULL:
|
||||
case LOGMODE_STDERR:
|
||||
break;
|
||||
}
|
||||
}
|
||||
75
src/logger.h
Normal file
75
src/logger.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#ifndef TINC_LOGGER_H
|
||||
#define TINC_LOGGER_H
|
||||
|
||||
/*
|
||||
logger.h -- header file for logger.c
|
||||
Copyright (C) 2003-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
typedef enum debug_t {
|
||||
DEBUG_NOTHING = 0, /* Quiet mode, only show starting/stopping of the daemon */
|
||||
DEBUG_ALWAYS = 0,
|
||||
DEBUG_CONNECTIONS = 1, /* Show (dis)connects of other tinc daemons via TCP */
|
||||
DEBUG_ERROR = 2, /* Show error messages received from other hosts */
|
||||
DEBUG_STATUS = 2, /* Show status messages received from other hosts */
|
||||
DEBUG_PROTOCOL = 3, /* Show the requests that are sent/received */
|
||||
DEBUG_META = 4, /* Show contents of every request that is sent/received */
|
||||
DEBUG_TRAFFIC = 5, /* Show network traffic information */
|
||||
DEBUG_PACKET = 6, /* Show contents of each packet that is being sent/received */
|
||||
DEBUG_SCARY_THINGS = 10, /* You have been warned */
|
||||
} debug_t;
|
||||
|
||||
typedef enum logmode_t {
|
||||
LOGMODE_NULL,
|
||||
LOGMODE_STDERR,
|
||||
LOGMODE_FILE,
|
||||
LOGMODE_SYSLOG
|
||||
} logmode_t;
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#define LOG_EMERG EVENTLOG_ERROR_TYPE
|
||||
#define LOG_ALERT EVENTLOG_ERROR_TYPE
|
||||
#define LOG_CRIT EVENTLOG_ERROR_TYPE
|
||||
#define LOG_ERR EVENTLOG_ERROR_TYPE
|
||||
#define LOG_WARNING EVENTLOG_WARNING_TYPE
|
||||
#define LOG_NOTICE EVENTLOG_INFORMATION_TYPE
|
||||
#define LOG_INFO EVENTLOG_INFORMATION_TYPE
|
||||
#define LOG_DEBUG EVENTLOG_INFORMATION_TYPE
|
||||
#else
|
||||
#ifndef HAVE_SYSLOG_H
|
||||
enum {
|
||||
LOG_EMERG,
|
||||
LOG_ALERT,
|
||||
LOG_CRIT,
|
||||
LOG_ERR,
|
||||
LOG_WARNING,
|
||||
LOG_NOTICE,
|
||||
LOG_INFO,
|
||||
LOG_DEBUG,
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern debug_t debug_level;
|
||||
extern void openlogger(const char *ident, logmode_t mode);
|
||||
extern void reopenlogger(void);
|
||||
extern void logger(int priority, const char *format, ...) __attribute__((__format__(printf, 2, 3)));
|
||||
extern void closelogger(void);
|
||||
|
||||
#define ifdebug(l) if(debug_level >= DEBUG_##l)
|
||||
|
||||
#endif
|
||||
258
src/meta.c
Normal file
258
src/meta.c
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
meta.c -- handle the meta communication
|
||||
Copyright (C) 2000-2017 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "connection.h"
|
||||
#include "logger.h"
|
||||
#include "meta.h"
|
||||
#include "net.h"
|
||||
#include "protocol.h"
|
||||
#include "proxy.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
bool send_meta(connection_t *c, const char *buffer, int length) {
|
||||
int outlen;
|
||||
int result;
|
||||
|
||||
ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
|
||||
c->name, c->hostname);
|
||||
|
||||
if(!c->outbuflen) {
|
||||
c->last_flushed_time = now;
|
||||
}
|
||||
|
||||
/* Find room in connection's buffer */
|
||||
if(length + c->outbuflen > c->outbufsize) {
|
||||
c->outbufsize = length + c->outbuflen;
|
||||
c->outbuf = xrealloc(c->outbuf, c->outbufsize);
|
||||
}
|
||||
|
||||
if(length + c->outbuflen + c->outbufstart > c->outbufsize) {
|
||||
memmove(c->outbuf, c->outbuf + c->outbufstart, c->outbuflen);
|
||||
c->outbufstart = 0;
|
||||
}
|
||||
|
||||
/* Add our data to buffer */
|
||||
if(c->status.encryptout) {
|
||||
/* Check encryption limits */
|
||||
if((uint64_t)length > c->outbudget) {
|
||||
ifdebug(META) logger(LOG_ERR, "Byte limit exceeded for encryption to %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
} else {
|
||||
c->outbudget -= length;
|
||||
}
|
||||
|
||||
result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen,
|
||||
&outlen, (unsigned char *)buffer, length);
|
||||
|
||||
if(!result || outlen < length) {
|
||||
logger(LOG_ERR, "Error while encrypting metadata to %s (%s): %s",
|
||||
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
} else if(outlen > length) {
|
||||
logger(LOG_EMERG, "Encrypted data too long! Heap corrupted!");
|
||||
abort();
|
||||
}
|
||||
|
||||
c->outbuflen += outlen;
|
||||
} else {
|
||||
memcpy(c->outbuf + c->outbufstart + c->outbuflen, buffer, length);
|
||||
c->outbuflen += length;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool flush_meta(connection_t *c) {
|
||||
int result;
|
||||
|
||||
ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s)",
|
||||
c->outbuflen, c->name, c->hostname);
|
||||
|
||||
while(c->outbuflen) {
|
||||
result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0);
|
||||
|
||||
if(result <= 0) {
|
||||
if(!errno || errno == EPIPE) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
|
||||
c->name, c->hostname);
|
||||
} else if(errno == EINTR) {
|
||||
continue;
|
||||
} else if(sockwouldblock(sockerrno)) {
|
||||
ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block",
|
||||
c->outbuflen, c->name, c->hostname);
|
||||
return true;
|
||||
} else {
|
||||
logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name,
|
||||
c->hostname, sockstrerror(sockerrno));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
c->outbufstart += result;
|
||||
c->outbuflen -= result;
|
||||
}
|
||||
|
||||
c->outbufstart = 0; /* avoid unnecessary memmoves */
|
||||
return true;
|
||||
}
|
||||
|
||||
void broadcast_meta(connection_t *from, const char *buffer, int length) {
|
||||
avl_node_t *node;
|
||||
connection_t *c;
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
|
||||
if(c != from && c->status.active) {
|
||||
send_meta(c, buffer, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool receive_meta(connection_t *c) {
|
||||
int oldlen, i, result;
|
||||
int lenin, lenout, reqlen;
|
||||
bool decrypted = false;
|
||||
char inbuf[MAXBUFSIZE];
|
||||
|
||||
/* Strategy:
|
||||
- Read as much as possible from the TCP socket in one go.
|
||||
- Decrypt it.
|
||||
- Check if a full request is in the input buffer.
|
||||
- If yes, process request and remove it from the buffer,
|
||||
then check again.
|
||||
- If not, keep stuff in buffer and exit.
|
||||
*/
|
||||
|
||||
lenin = recv(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen, 0);
|
||||
|
||||
if(lenin <= 0) {
|
||||
if(!lenin || !errno) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
|
||||
c->name, c->hostname);
|
||||
} else if(sockwouldblock(sockerrno)) {
|
||||
return true;
|
||||
} else
|
||||
logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
|
||||
c->name, c->hostname, sockstrerror(sockerrno));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
oldlen = c->buflen;
|
||||
c->buflen += lenin;
|
||||
|
||||
while(lenin > 0) {
|
||||
reqlen = 0;
|
||||
|
||||
/* Is it proxy metadata? */
|
||||
|
||||
if(c->allow_request == PROXY) {
|
||||
reqlen = receive_proxy_meta(c);
|
||||
|
||||
if(reqlen < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
goto consume;
|
||||
}
|
||||
|
||||
/* Decrypt */
|
||||
|
||||
if(c->status.decryptin && !decrypted) {
|
||||
/* Check decryption limits */
|
||||
if((uint64_t)lenin > c->inbudget) {
|
||||
ifdebug(META) logger(LOG_ERR, "Byte limit exceeded for decryption from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
} else {
|
||||
c->inbudget -= lenin;
|
||||
}
|
||||
|
||||
result = EVP_DecryptUpdate(c->inctx, (unsigned char *)inbuf, &lenout, (unsigned char *)c->buffer + oldlen, lenin);
|
||||
|
||||
if(!result || lenout != lenin) {
|
||||
logger(LOG_ERR, "Error while decrypting metadata from %s (%s): %s",
|
||||
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(c->buffer + oldlen, inbuf, lenin);
|
||||
decrypted = true;
|
||||
}
|
||||
|
||||
/* Are we receiving a TCPpacket? */
|
||||
|
||||
if(c->tcplen) {
|
||||
if(c->tcplen <= c->buflen) {
|
||||
if(c->allow_request != ALL) {
|
||||
logger(LOG_ERR, "Got unauthorized TCP packet from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
receive_tcppacket(c, c->buffer, c->tcplen);
|
||||
reqlen = c->tcplen;
|
||||
c->tcplen = 0;
|
||||
}
|
||||
} else {
|
||||
/* Otherwise we are waiting for a request */
|
||||
|
||||
for(i = oldlen; i < c->buflen; i++) {
|
||||
if(c->buffer[i] == '\n') {
|
||||
c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */
|
||||
c->reqlen = reqlen = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(reqlen && !receive_request(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
consume:
|
||||
|
||||
if(reqlen) {
|
||||
c->buflen -= reqlen;
|
||||
lenin -= reqlen - oldlen;
|
||||
memmove(c->buffer, c->buffer + reqlen, c->buflen);
|
||||
oldlen = 0;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(c->buflen >= MAXBUFSIZE) {
|
||||
logger(LOG_ERR, "Metadata read buffer overflow for %s (%s)",
|
||||
c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
31
src/meta.h
Normal file
31
src/meta.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef TINC_META_H
|
||||
#define TINC_META_H
|
||||
|
||||
/*
|
||||
meta.h -- header for meta.c
|
||||
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
extern bool send_meta(struct connection_t *c, const char *buffer, int length);
|
||||
extern void broadcast_meta(struct connection_t *c, const char *buffer, int length);
|
||||
extern bool flush_meta(struct connection_t *c);
|
||||
extern bool receive_meta(struct connection_t *c);
|
||||
|
||||
#endif
|
||||
75
src/mingw/common.h
Normal file
75
src/mingw/common.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* TAP-Win32 -- A kernel driver to provide virtual tap device functionality
|
||||
* on Windows. Originally derived from the CIPE-Win32
|
||||
* project by Damion K. Wilson, with extensive modifications by
|
||||
* James Yonan.
|
||||
*
|
||||
* All source code which derives from the CIPE-Win32 project is
|
||||
* Copyright (C) Damion K. Wilson, 2003, and is released under the
|
||||
* GPL version 2 (see below).
|
||||
*
|
||||
* All other source code is Copyright (C) James Yonan, 2003-2004,
|
||||
* and is released under the GPL version 2 (see below).
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//===============================================
|
||||
// This file is included both by OpenVPN and
|
||||
// the TAP-Win32 driver and contains definitions
|
||||
// common to both.
|
||||
//===============================================
|
||||
|
||||
//=============
|
||||
// TAP IOCTLs
|
||||
//=============
|
||||
|
||||
#define TAP_CONTROL_CODE(request,method) \
|
||||
CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
|
||||
|
||||
#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED)
|
||||
|
||||
//=================
|
||||
// Registry keys
|
||||
//=================
|
||||
|
||||
#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
||||
|
||||
#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
||||
|
||||
//======================
|
||||
// Filesystem prefixes
|
||||
//======================
|
||||
|
||||
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
|
||||
#define SYSDEVICEDIR "\\Device\\"
|
||||
#define USERDEVICEDIR "\\DosDevices\\Global\\"
|
||||
#define TAPSUFFIX ".tap"
|
||||
|
||||
//=========================================================
|
||||
// TAP_COMPONENT_ID -- This string defines the TAP driver
|
||||
// type -- different component IDs can reside in the system
|
||||
// simultaneously.
|
||||
//=========================================================
|
||||
|
||||
#define TAP_COMPONENT_ID "tap0801"
|
||||
322
src/mingw/device.c
Normal file
322
src/mingw/device.c
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a MinGW environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../net.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int device_fd = -1;
|
||||
static HANDLE device_handle = INVALID_HANDLE_VALUE;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static const char *device_info = "Windows tap device";
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
extern char *myport;
|
||||
OVERLAPPED r_overlapped;
|
||||
OVERLAPPED w_overlapped;
|
||||
|
||||
static DWORD WINAPI tapreader(void *bla) {
|
||||
int status;
|
||||
DWORD len;
|
||||
vpn_packet_t packet;
|
||||
int errors = 0;
|
||||
|
||||
logger(LOG_DEBUG, "Tap reader running");
|
||||
|
||||
/* Read from tap device and send to parent */
|
||||
|
||||
r_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
for(;;) {
|
||||
ResetEvent(r_overlapped.hEvent);
|
||||
|
||||
status = ReadFile(device_handle, packet.data, MTU, &len, &r_overlapped);
|
||||
|
||||
if(!status) {
|
||||
if(GetLastError() == ERROR_IO_PENDING) {
|
||||
WaitForSingleObject(r_overlapped.hEvent, INFINITE);
|
||||
|
||||
if(!GetOverlappedResult(device_handle, &r_overlapped, &len, FALSE)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
errors++;
|
||||
|
||||
if(errors >= 10) {
|
||||
EnterCriticalSection(&mutex);
|
||||
running = false;
|
||||
LeaveCriticalSection(&mutex);
|
||||
}
|
||||
|
||||
usleep(1000000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
errors = 0;
|
||||
packet.len = len;
|
||||
packet.priority = 0;
|
||||
|
||||
EnterCriticalSection(&mutex);
|
||||
route(myself, &packet);
|
||||
LeaveCriticalSection(&mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool setup_device(void) {
|
||||
HKEY key, key2;
|
||||
int i;
|
||||
|
||||
char regpath[1024];
|
||||
char adapterid[1024];
|
||||
char adaptername[1024];
|
||||
char tapname[1024];
|
||||
DWORD len;
|
||||
unsigned long status;
|
||||
|
||||
bool found = false;
|
||||
|
||||
int err;
|
||||
HANDLE thread;
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
||||
get_config_string(lookup_config(config_tree, "Interface"), &iface);
|
||||
|
||||
if(device && iface) {
|
||||
logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
|
||||
}
|
||||
|
||||
/* Open registry and look for network adapters */
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
||||
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
for(i = 0; ; i++) {
|
||||
len = sizeof(adapterid);
|
||||
|
||||
if(RegEnumKeyEx(key, i, adapterid, &len, 0, 0, 0, NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find out more about this adapter */
|
||||
|
||||
snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapterid);
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
len = sizeof(adaptername);
|
||||
err = RegQueryValueEx(key2, "Name", 0, 0, (LPBYTE)adaptername, &len);
|
||||
|
||||
RegCloseKey(key2);
|
||||
|
||||
if(err) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(device) {
|
||||
if(!strcmp(device, adapterid)) {
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(iface) {
|
||||
if(!strcmp(iface, adaptername)) {
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
|
||||
device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
|
||||
|
||||
if(device_handle != INVALID_HANDLE_VALUE) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(key);
|
||||
|
||||
if(!found) {
|
||||
logger(LOG_ERR, "No Windows tap device found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!device) {
|
||||
device = xstrdup(adapterid);
|
||||
}
|
||||
|
||||
if(!iface) {
|
||||
iface = xstrdup(adaptername);
|
||||
}
|
||||
|
||||
/* Try to open the corresponding tap device */
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device);
|
||||
device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
|
||||
}
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
logger(LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get MAC address from tap device */
|
||||
|
||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
|
||||
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(routing_mode == RMODE_ROUTER) {
|
||||
overwrite_mac = 1;
|
||||
}
|
||||
|
||||
/* Create overlapped events for tap I/O */
|
||||
|
||||
r_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
w_overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
||||
|
||||
/* Start the tap reader */
|
||||
|
||||
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
|
||||
|
||||
if(!thread) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "CreateThread", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set media status for newer TAP-Win32 devices */
|
||||
|
||||
status = true;
|
||||
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
|
||||
|
||||
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
CloseHandle(device_handle);
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
DWORD lenout;
|
||||
static vpn_packet_t queue;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
/* Check if there is something in progress */
|
||||
|
||||
if(queue.len) {
|
||||
DWORD size;
|
||||
BOOL success = GetOverlappedResult(device_handle, &w_overlapped, &size, FALSE);
|
||||
|
||||
if(success) {
|
||||
ResetEvent(&w_overlapped);
|
||||
queue.len = 0;
|
||||
} else {
|
||||
int err = GetLastError();
|
||||
|
||||
if(err != ERROR_IO_INCOMPLETE) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error completing previously queued write: %s", winerror(err));
|
||||
ResetEvent(&w_overlapped);
|
||||
queue.len = 0;
|
||||
} else {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Previous overlapped write still in progress");
|
||||
// drop this packet
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, try to write. */
|
||||
|
||||
memcpy(queue.data, packet->data, packet->len);
|
||||
|
||||
if(!WriteFile(device_handle, queue.data, packet->len, &lenout, &w_overlapped)) {
|
||||
int err = GetLastError();
|
||||
|
||||
if(err != ERROR_IO_PENDING) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write is being done asynchronously.
|
||||
queue.len = packet->len;
|
||||
} else {
|
||||
// Write was completed immediately.
|
||||
ResetEvent(&w_overlapped);
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
247
src/multicast_device.c
Normal file
247
src/multicast_device.c
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
device.c -- multicast socket
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "device.h"
|
||||
#include "net.h"
|
||||
#include "logger.h"
|
||||
#include "netutl.h"
|
||||
#include "utils.h"
|
||||
#include "route.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static const char *device_info = "multicast socket";
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static struct addrinfo *ai = NULL;
|
||||
static mac_t ignore_src = {{0}};
|
||||
|
||||
static bool setup_device(void) {
|
||||
char *host;
|
||||
char *port;
|
||||
char *space;
|
||||
int ttl = 1;
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Interface"), &iface);
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
logger(LOG_ERR, "Device variable required for %s", device_info);
|
||||
return false;
|
||||
}
|
||||
|
||||
host = xstrdup(device);
|
||||
space = strchr(host, ' ');
|
||||
|
||||
if(!space) {
|
||||
logger(LOG_ERR, "Port number required for %s", device_info);
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
*space++ = 0;
|
||||
port = space;
|
||||
space = strchr(port, ' ');
|
||||
|
||||
if(space) {
|
||||
*space++ = 0;
|
||||
ttl = atoi(space);
|
||||
}
|
||||
|
||||
ai = str2addrinfo(host, port, SOCK_DGRAM);
|
||||
|
||||
if(!ai) {
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
device_fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno));
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
static const int one = 1;
|
||||
setsockopt(device_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
|
||||
|
||||
if(bind(device_fd, ai->ai_addr, ai->ai_addrlen)) {
|
||||
closesocket(device_fd);
|
||||
logger(LOG_ERR, "Can't bind to %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(ai->ai_family) {
|
||||
#ifdef IP_ADD_MEMBERSHIP
|
||||
|
||||
case AF_INET: {
|
||||
struct ip_mreq mreq;
|
||||
struct sockaddr_in in;
|
||||
memcpy(&in, ai->ai_addr, sizeof(in));
|
||||
mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr;
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq))) {
|
||||
logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
closesocket(device_fd);
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef IP_MULTICAST_LOOP
|
||||
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof(one));
|
||||
#endif
|
||||
#ifdef IP_MULTICAST_TTL
|
||||
setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof(ttl));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef IPV6_JOIN_GROUP
|
||||
|
||||
case AF_INET6: {
|
||||
struct ipv6_mreq mreq;
|
||||
struct sockaddr_in6 in6;
|
||||
memcpy(&in6, ai->ai_addr, sizeof(in6));
|
||||
memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof(mreq.ipv6mr_multiaddr));
|
||||
mreq.ipv6mr_interface = in6.sin6_scope_id;
|
||||
|
||||
if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof(mreq))) {
|
||||
logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
closesocket(device_fd);
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef IPV6_MULTICAST_LOOP
|
||||
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof(one));
|
||||
#endif
|
||||
#ifdef IPV6_MULTICAST_HOPS
|
||||
setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof(ttl));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
logger(LOG_ERR, "Multicast for address family %x unsupported", ai->ai_family);
|
||||
closesocket(device_fd);
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(host);
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
|
||||
free(device);
|
||||
free(iface);
|
||||
|
||||
if(ai) {
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin;
|
||||
|
||||
if((lenin = recv(device_fd, (void *)packet->data, MTU, 0)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!memcmp(&ignore_src, packet->data + 6, sizeof(ignore_src))) {
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
|
||||
packet->len = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
packet->len = lenin;
|
||||
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(sendto(device_fd, (void *)packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
memcpy(&ignore_src, packet->data + 6, sizeof(ignore_src));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t multicast_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
static bool not_supported(void) {
|
||||
logger(LOG_ERR, "Raw socket device not supported on this platform");
|
||||
return false;
|
||||
}
|
||||
|
||||
const devops_t multicast_devops = {
|
||||
.setup = not_supported,
|
||||
.close = NULL,
|
||||
.read = NULL,
|
||||
.write = NULL,
|
||||
.dump_stats = NULL,
|
||||
};
|
||||
#endif
|
||||
711
src/net.c
Normal file
711
src/net.c
Normal file
|
|
@ -0,0 +1,711 @@
|
|||
/*
|
||||
net.c -- most of the network code
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2011 Loïc Grenié <loic.grenie@gmail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "avl_tree.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
#include "device.h"
|
||||
#include "event.h"
|
||||
#include "graph.h"
|
||||
#include "logger.h"
|
||||
#include "meta.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "process.h"
|
||||
#include "protocol.h"
|
||||
#include "route.h"
|
||||
#include "subnet.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
bool do_purge = false;
|
||||
volatile bool running = false;
|
||||
#ifdef HAVE_PSELECT
|
||||
bool graph_dump = false;
|
||||
#endif
|
||||
|
||||
time_t now = 0;
|
||||
int contradicting_add_edge = 0;
|
||||
int contradicting_del_edge = 0;
|
||||
static int sleeptime = 10;
|
||||
|
||||
/* Purge edges and subnets of unreachable nodes. Use carefully. */
|
||||
|
||||
static void purge(void) {
|
||||
avl_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
|
||||
node_t *n;
|
||||
edge_t *e;
|
||||
subnet_t *s;
|
||||
|
||||
ifdebug(PROTOCOL) logger(LOG_DEBUG, "Purging unreachable nodes");
|
||||
|
||||
/* Remove all edges and subnets owned by unreachable nodes. */
|
||||
|
||||
for(nnode = node_tree->head; nnode; nnode = nnext) {
|
||||
nnext = nnode->next;
|
||||
n = nnode->data;
|
||||
|
||||
if(!n->status.reachable) {
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Purging node %s (%s)", n->name,
|
||||
n->hostname);
|
||||
|
||||
for(snode = n->subnet_tree->head; snode; snode = snext) {
|
||||
snext = snode->next;
|
||||
s = snode->data;
|
||||
send_del_subnet(everyone, s);
|
||||
|
||||
if(!strictsubnets) {
|
||||
subnet_del(n, s);
|
||||
}
|
||||
}
|
||||
|
||||
for(enode = n->edge_tree->head; enode; enode = enext) {
|
||||
enext = enode->next;
|
||||
e = enode->data;
|
||||
|
||||
if(!tunnelserver) {
|
||||
send_del_edge(everyone, e);
|
||||
}
|
||||
|
||||
edge_del(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if anyone else claims to have an edge to an unreachable node. If not, delete node. */
|
||||
|
||||
for(nnode = node_tree->head; nnode; nnode = nnext) {
|
||||
nnext = nnode->next;
|
||||
n = nnode->data;
|
||||
|
||||
if(!n->status.reachable) {
|
||||
for(enode = edge_weight_tree->head; enode; enode = enext) {
|
||||
enext = enode->next;
|
||||
e = enode->data;
|
||||
|
||||
if(e->to == n) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!enode && (!strictsubnets || !n->subnet_tree->head))
|
||||
/* in strictsubnets mode do not delete nodes with subnets */
|
||||
{
|
||||
node_del(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
put all file descriptors in an fd_set array
|
||||
While we're at it, purge stuff that needs to be removed.
|
||||
*/
|
||||
static int build_fdset(fd_set *readset, fd_set *writeset) {
|
||||
avl_node_t *node, *next;
|
||||
connection_t *c;
|
||||
int i, max = 0;
|
||||
|
||||
FD_ZERO(readset);
|
||||
FD_ZERO(writeset);
|
||||
|
||||
for(node = connection_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
c = node->data;
|
||||
|
||||
if(c->status.remove) {
|
||||
connection_del(c);
|
||||
|
||||
if(!connection_tree->head) {
|
||||
purge();
|
||||
}
|
||||
} else {
|
||||
FD_SET(c->socket, readset);
|
||||
|
||||
if(c->outbuflen > 0 || c->status.connecting) {
|
||||
FD_SET(c->socket, writeset);
|
||||
}
|
||||
|
||||
if(c->socket > max) {
|
||||
max = c->socket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < listen_sockets; i++) {
|
||||
FD_SET(listen_socket[i].tcp, readset);
|
||||
|
||||
if(listen_socket[i].tcp > max) {
|
||||
max = listen_socket[i].tcp;
|
||||
}
|
||||
|
||||
FD_SET(listen_socket[i].udp, readset);
|
||||
|
||||
if(listen_socket[i].udp > max) {
|
||||
max = listen_socket[i].udp;
|
||||
}
|
||||
}
|
||||
|
||||
if(device_fd >= 0) {
|
||||
FD_SET(device_fd, readset);
|
||||
}
|
||||
|
||||
if(device_fd > max) {
|
||||
max = device_fd;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/* Put a misbehaving connection in the tarpit */
|
||||
void tarpit(int fd) {
|
||||
static int pits[10] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
||||
static int next_pit = 0;
|
||||
|
||||
if(pits[next_pit] != -1) {
|
||||
closesocket(pits[next_pit]);
|
||||
}
|
||||
|
||||
pits[next_pit++] = fd;
|
||||
|
||||
if(next_pit >= (int)(sizeof pits / sizeof pits[0])) {
|
||||
next_pit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Terminate a connection:
|
||||
- Close the socket
|
||||
- Remove associated edge and tell other connections about it if report = true
|
||||
- Check if we need to retry making an outgoing connection
|
||||
- Deactivate the host
|
||||
*/
|
||||
void terminate_connection(connection_t *c, bool report) {
|
||||
if(c->status.remove) {
|
||||
return;
|
||||
}
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Closing connection with %s (%s)",
|
||||
c->name, c->hostname);
|
||||
|
||||
c->status.remove = true;
|
||||
c->status.active = false;
|
||||
|
||||
if(c->node) {
|
||||
c->node->connection = NULL;
|
||||
}
|
||||
|
||||
if(c->socket) {
|
||||
if(c->status.tarpit) {
|
||||
tarpit(c->socket);
|
||||
} else {
|
||||
closesocket(c->socket);
|
||||
}
|
||||
}
|
||||
|
||||
if(c->edge) {
|
||||
if(!c->node) {
|
||||
logger(LOG_ERR, "Connection to %s (%s) has an edge but node is NULL!", c->name, c->hostname);
|
||||
// And that should never happen.
|
||||
abort();
|
||||
}
|
||||
|
||||
if(report && !tunnelserver) {
|
||||
send_del_edge(everyone, c->edge);
|
||||
}
|
||||
|
||||
edge_del(c->edge);
|
||||
c->edge = NULL;
|
||||
|
||||
/* Run MST and SSSP algorithms */
|
||||
|
||||
graph();
|
||||
|
||||
/* If the node is not reachable anymore but we remember it had an edge to us, clean it up */
|
||||
|
||||
if(report && !c->node->status.reachable) {
|
||||
edge_t *e;
|
||||
e = lookup_edge(c->node, myself);
|
||||
|
||||
if(e) {
|
||||
if(!tunnelserver) {
|
||||
send_del_edge(everyone, e);
|
||||
}
|
||||
|
||||
edge_del(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_connection_partially(c);
|
||||
|
||||
/* Check if this was our outgoing connection */
|
||||
|
||||
if(c->outgoing) {
|
||||
c->status.remove = false;
|
||||
do_outgoing_connection(c);
|
||||
}
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
/* Clean up dead proxy processes */
|
||||
|
||||
while(waitpid(-1, NULL, WNOHANG) > 0);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Check if the other end is active.
|
||||
If we have sent packets, but didn't receive any,
|
||||
then possibly the other end is dead. We send a
|
||||
PING request over the meta connection. If the other
|
||||
end does not reply in time, we consider them dead
|
||||
and close the connection.
|
||||
*/
|
||||
static void check_dead_connections(void) {
|
||||
avl_node_t *node, *next;
|
||||
connection_t *c;
|
||||
|
||||
for(node = connection_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
c = node->data;
|
||||
|
||||
if(c->last_ping_time + pingtimeout <= now) {
|
||||
if(c->status.active) {
|
||||
if(c->status.pinged) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
|
||||
c->name, c->hostname, (long)(now - c->last_ping_time));
|
||||
c->status.timeout = true;
|
||||
terminate_connection(c, true);
|
||||
} else if(c->last_ping_time + pinginterval <= now) {
|
||||
send_ping(c);
|
||||
}
|
||||
} else {
|
||||
if(c->status.remove) {
|
||||
logger(LOG_WARNING, "Old connection_t for %s (%s) status %04x still lingering, deleting...",
|
||||
c->name, c->hostname, bitfield_to_int(&c->status, sizeof(c->status)));
|
||||
connection_del(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication",
|
||||
c->name, c->hostname);
|
||||
|
||||
if(c->status.connecting) {
|
||||
c->status.connecting = false;
|
||||
closesocket(c->socket);
|
||||
do_outgoing_connection(c);
|
||||
} else {
|
||||
c->status.tarpit = true;
|
||||
terminate_connection(c, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout <= now) {
|
||||
if(c->status.active) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO,
|
||||
"%s (%s) could not flush for %ld seconds (%d bytes remaining)",
|
||||
c->name, c->hostname, (long)(now - c->last_flushed_time), c->outbuflen);
|
||||
c->status.timeout = true;
|
||||
terminate_connection(c, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
check all connections to see if anything
|
||||
happened on their sockets
|
||||
*/
|
||||
static void check_network_activity(fd_set *readset, fd_set *writeset) {
|
||||
connection_t *c;
|
||||
avl_node_t *node;
|
||||
int result, i;
|
||||
socklen_t len = sizeof(result);
|
||||
vpn_packet_t packet;
|
||||
static int errors = 0;
|
||||
|
||||
/* check input from kernel */
|
||||
if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
|
||||
if(devops.read(&packet)) {
|
||||
if(packet.len) {
|
||||
errors = 0;
|
||||
packet.priority = 0;
|
||||
route(myself, &packet);
|
||||
}
|
||||
} else {
|
||||
usleep(errors * 50000);
|
||||
errors++;
|
||||
|
||||
if(errors > 10) {
|
||||
logger(LOG_ERR, "Too many errors from %s, exiting!", device);
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check meta connections */
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
|
||||
if(c->status.remove) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(FD_ISSET(c->socket, writeset)) {
|
||||
if(c->status.connecting) {
|
||||
c->status.connecting = false;
|
||||
getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len);
|
||||
|
||||
if(!result) {
|
||||
finish_connecting(c);
|
||||
} else {
|
||||
ifdebug(CONNECTIONS) logger(LOG_DEBUG,
|
||||
"Error while connecting to %s (%s): %s",
|
||||
c->name, c->hostname, sockstrerror(result));
|
||||
closesocket(c->socket);
|
||||
do_outgoing_connection(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(!flush_meta(c)) {
|
||||
terminate_connection(c, c->status.active);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(FD_ISSET(c->socket, readset)) {
|
||||
if(!receive_meta(c)) {
|
||||
c->status.tarpit = !c->status.active;
|
||||
terminate_connection(c, c->status.active);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < listen_sockets; i++) {
|
||||
if(FD_ISSET(listen_socket[i].udp, readset)) {
|
||||
handle_incoming_vpn_data(i);
|
||||
}
|
||||
|
||||
if(FD_ISSET(listen_socket[i].tcp, readset)) {
|
||||
handle_new_meta_connection(listen_socket[i].tcp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
this is where it all happens...
|
||||
*/
|
||||
int main_loop(void) {
|
||||
fd_set readset, writeset;
|
||||
#ifdef HAVE_PSELECT
|
||||
struct timespec tv;
|
||||
sigset_t omask, block_mask;
|
||||
time_t next_event;
|
||||
#else
|
||||
struct timeval tv;
|
||||
#endif
|
||||
int r, maxfd;
|
||||
time_t last_ping_check, last_config_check, last_graph_dump;
|
||||
event_t *event;
|
||||
|
||||
last_ping_check = now;
|
||||
last_config_check = now;
|
||||
last_graph_dump = now;
|
||||
|
||||
srand(now);
|
||||
|
||||
#ifdef HAVE_PSELECT
|
||||
|
||||
if(lookup_config(config_tree, "GraphDumpFile")) {
|
||||
graph_dump = true;
|
||||
}
|
||||
|
||||
/* Block SIGHUP & SIGALRM */
|
||||
sigemptyset(&block_mask);
|
||||
sigaddset(&block_mask, SIGHUP);
|
||||
sigaddset(&block_mask, SIGALRM);
|
||||
sigprocmask(SIG_BLOCK, &block_mask, &omask);
|
||||
#endif
|
||||
|
||||
running = true;
|
||||
|
||||
while(running) {
|
||||
#ifdef HAVE_PSELECT
|
||||
next_event = last_ping_check + pingtimeout;
|
||||
|
||||
if(graph_dump && next_event > last_graph_dump + 60) {
|
||||
next_event = last_graph_dump + 60;
|
||||
}
|
||||
|
||||
if((event = peek_next_event()) && next_event > event->time) {
|
||||
next_event = event->time;
|
||||
}
|
||||
|
||||
if(next_event <= now) {
|
||||
tv.tv_sec = 0;
|
||||
} else {
|
||||
tv.tv_sec = next_event - now;
|
||||
}
|
||||
|
||||
tv.tv_nsec = 0;
|
||||
#else
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
#endif
|
||||
|
||||
maxfd = build_fdset(&readset, &writeset);
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
LeaveCriticalSection(&mutex);
|
||||
#endif
|
||||
#ifdef HAVE_PSELECT
|
||||
r = pselect(maxfd + 1, &readset, &writeset, NULL, &tv, &omask);
|
||||
#else
|
||||
r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
|
||||
#endif
|
||||
now = time(NULL);
|
||||
#ifdef HAVE_MINGW
|
||||
EnterCriticalSection(&mutex);
|
||||
#endif
|
||||
|
||||
if(r < 0) {
|
||||
if(!sockwouldblock(sockerrno)) {
|
||||
logger(LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno));
|
||||
dump_connections();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(r > 0) {
|
||||
check_network_activity(&readset, &writeset);
|
||||
}
|
||||
|
||||
if(do_purge) {
|
||||
purge();
|
||||
do_purge = false;
|
||||
}
|
||||
|
||||
/* Let's check if everybody is still alive */
|
||||
|
||||
if(last_ping_check + pingtimeout <= now) {
|
||||
check_dead_connections();
|
||||
last_ping_check = now;
|
||||
|
||||
if(routing_mode == RMODE_SWITCH) {
|
||||
age_subnets();
|
||||
}
|
||||
|
||||
age_past_requests();
|
||||
|
||||
/* Should we regenerate our key? */
|
||||
|
||||
if(keyexpires <= now) {
|
||||
avl_node_t *node;
|
||||
node_t *n;
|
||||
|
||||
ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
|
||||
if(n->inkey) {
|
||||
free(n->inkey);
|
||||
n->inkey = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
send_key_changed();
|
||||
keyexpires = now + keylifetime;
|
||||
}
|
||||
|
||||
/* Detect ADD_EDGE/DEL_EDGE storms that are caused when
|
||||
* two tinc daemons with the same name are on the VPN.
|
||||
* If so, sleep a while. If this happens multiple times
|
||||
* in a row, sleep longer. */
|
||||
|
||||
if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
|
||||
logger(LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
|
||||
usleep(sleeptime * 1000000LL);
|
||||
sleeptime *= 2;
|
||||
|
||||
if(sleeptime < 0) {
|
||||
sleeptime = 3600;
|
||||
}
|
||||
} else {
|
||||
sleeptime /= 2;
|
||||
|
||||
if(sleeptime < 10) {
|
||||
sleeptime = 10;
|
||||
}
|
||||
}
|
||||
|
||||
contradicting_add_edge = 0;
|
||||
contradicting_del_edge = 0;
|
||||
}
|
||||
|
||||
if(sigalrm) {
|
||||
avl_node_t *node;
|
||||
logger(LOG_INFO, "Flushing event queue");
|
||||
expire_events();
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
connection_t *c = node->data;
|
||||
|
||||
if(c->status.active) {
|
||||
send_ping(c);
|
||||
}
|
||||
}
|
||||
|
||||
sigalrm = false;
|
||||
}
|
||||
|
||||
while((event = get_expired_event())) {
|
||||
event->handler(event->data);
|
||||
free_event(event);
|
||||
}
|
||||
|
||||
if(sighup) {
|
||||
connection_t *c;
|
||||
avl_node_t *node, *next;
|
||||
char *fname;
|
||||
struct stat s;
|
||||
|
||||
sighup = false;
|
||||
|
||||
reopenlogger();
|
||||
|
||||
/* Reread our own configuration file */
|
||||
|
||||
exit_configuration(&config_tree);
|
||||
init_configuration(&config_tree);
|
||||
|
||||
if(!read_server_config()) {
|
||||
logger(LOG_ERR, "Unable to reread configuration file, exiting.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Cancel non-active outgoing connections */
|
||||
|
||||
for(node = connection_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
c = node->data;
|
||||
|
||||
c->outgoing = NULL;
|
||||
|
||||
if(c->status.connecting) {
|
||||
terminate_connection(c, false);
|
||||
connection_del(c);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wipe list of outgoing connections */
|
||||
|
||||
for(list_node_t *node = outgoing_list->head; node; node = node->next) {
|
||||
outgoing_t *outgoing = node->data;
|
||||
|
||||
if(outgoing->event) {
|
||||
event_del(outgoing->event);
|
||||
}
|
||||
}
|
||||
|
||||
list_delete_list(outgoing_list);
|
||||
|
||||
/* Close connections to hosts that have a changed or deleted host config file */
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
|
||||
|
||||
if(stat(fname, &s) || s.st_mtime > last_config_check) {
|
||||
terminate_connection(c, c->status.active);
|
||||
}
|
||||
|
||||
free(fname);
|
||||
}
|
||||
|
||||
last_config_check = now;
|
||||
|
||||
/* If StrictSubnet is set, expire deleted Subnets and read new ones in */
|
||||
|
||||
if(strictsubnets) {
|
||||
subnet_t *subnet;
|
||||
|
||||
for(node = subnet_tree->head; node; node = node->next) {
|
||||
subnet = node->data;
|
||||
subnet->expires = 1;
|
||||
}
|
||||
|
||||
load_all_subnets();
|
||||
|
||||
for(node = subnet_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
subnet = node->data;
|
||||
|
||||
if(subnet->expires == 1) {
|
||||
send_del_subnet(everyone, subnet);
|
||||
|
||||
if(subnet->owner->status.reachable) {
|
||||
subnet_update(subnet->owner, subnet, false);
|
||||
}
|
||||
|
||||
subnet_del(subnet->owner, subnet);
|
||||
} else if(subnet->expires == -1) {
|
||||
subnet->expires = 0;
|
||||
} else {
|
||||
send_add_subnet(everyone, subnet);
|
||||
|
||||
if(subnet->owner->status.reachable) {
|
||||
subnet_update(subnet->owner, subnet, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to make outgoing connections */
|
||||
|
||||
try_outgoing_connections();
|
||||
}
|
||||
|
||||
/* Dump graph if wanted every 60 seconds*/
|
||||
|
||||
if(last_graph_dump + 60 <= now) {
|
||||
dump_graph();
|
||||
last_graph_dump = now;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_PSELECT
|
||||
/* Restore SIGHUP & SIGALARM mask */
|
||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
161
src/net.h
Normal file
161
src/net.h
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
#ifndef TINC_NET_H
|
||||
#define TINC_NET_H
|
||||
|
||||
/*
|
||||
net.h -- header for net.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "ipv6.h"
|
||||
|
||||
#ifdef ENABLE_JUMBOGRAMS
|
||||
#define MTU 9018 /* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
|
||||
#else
|
||||
#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
|
||||
#endif
|
||||
|
||||
#define MAXSIZE (MTU + 4 + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */
|
||||
#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */
|
||||
|
||||
#define MAXSOCKETS 128 /* Overkill... */
|
||||
|
||||
typedef struct mac_t {
|
||||
uint8_t x[6];
|
||||
} mac_t;
|
||||
|
||||
typedef struct ipv4_t {
|
||||
uint8_t x[4];
|
||||
} ipv4_t;
|
||||
|
||||
typedef struct ipv6_t {
|
||||
uint16_t x[8];
|
||||
} ipv6_t;
|
||||
|
||||
typedef uint16_t length_t;
|
||||
|
||||
#define AF_UNKNOWN 255
|
||||
|
||||
struct sockaddr_unknown {
|
||||
uint16_t family;
|
||||
uint16_t pad1;
|
||||
uint32_t pad2;
|
||||
char *address;
|
||||
char *port;
|
||||
};
|
||||
|
||||
typedef union sockaddr_t {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
struct sockaddr_unknown unknown;
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
|
||||
struct sockaddr_storage storage;
|
||||
#endif
|
||||
} sockaddr_t;
|
||||
|
||||
#ifdef SA_LEN
|
||||
#define SALEN(s) SA_LEN(&s)
|
||||
#else
|
||||
#define SALEN(s) (s.sa_family==AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6))
|
||||
#endif
|
||||
|
||||
typedef struct vpn_packet_t {
|
||||
length_t len; /* the actual number of bytes in the `data' field */
|
||||
int priority; /* priority or TOS */
|
||||
uint32_t seqno; /* 32 bits sequence number (network byte order of course) */
|
||||
uint8_t data[MAXSIZE];
|
||||
} vpn_packet_t;
|
||||
|
||||
typedef struct listen_socket_t {
|
||||
int tcp;
|
||||
int udp;
|
||||
sockaddr_t sa;
|
||||
int priority;
|
||||
} listen_socket_t;
|
||||
|
||||
#include "conf.h"
|
||||
#include "list.h"
|
||||
|
||||
typedef struct outgoing_t {
|
||||
char *name;
|
||||
int timeout;
|
||||
struct config_t *cfg;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *aip;
|
||||
struct event *event;
|
||||
} outgoing_t;
|
||||
|
||||
extern list_t *outgoing_list;
|
||||
|
||||
extern int maxoutbufsize;
|
||||
extern int seconds_till_retry;
|
||||
extern int addressfamily;
|
||||
extern unsigned replaywin;
|
||||
extern bool localdiscovery;
|
||||
|
||||
extern listen_socket_t listen_socket[MAXSOCKETS];
|
||||
extern int listen_sockets;
|
||||
extern int keyexpires;
|
||||
extern int keylifetime;
|
||||
extern int udp_rcvbuf;
|
||||
extern int udp_sndbuf;
|
||||
extern bool do_prune;
|
||||
extern bool do_purge;
|
||||
extern char *myport;
|
||||
extern time_t now;
|
||||
extern int contradicting_add_edge;
|
||||
extern int contradicting_del_edge;
|
||||
|
||||
extern volatile bool running;
|
||||
|
||||
/* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
|
||||
#include "connection.h"
|
||||
#include "node.h"
|
||||
|
||||
extern void retry_outgoing(outgoing_t *outgoing);
|
||||
extern void handle_incoming_vpn_data(int sock);
|
||||
extern void finish_connecting(struct connection_t *c);
|
||||
extern void do_outgoing_connection(struct connection_t *c);
|
||||
extern bool handle_new_meta_connection(int sock);
|
||||
extern int setup_listen_socket(const sockaddr_t *sa);
|
||||
extern int setup_vpn_in_socket(const sockaddr_t *sa);
|
||||
extern void send_packet(const struct node_t *n, vpn_packet_t *packet);
|
||||
extern void receive_tcppacket(struct connection_t *c, const char *buffer, length_t len);
|
||||
extern void broadcast_packet(const struct node_t *, vpn_packet_t *packet);
|
||||
extern char *get_name(void);
|
||||
extern bool setup_network(void);
|
||||
extern void setup_outgoing_connection(struct outgoing_t *outgoing);
|
||||
extern void try_outgoing_connections(void);
|
||||
extern void close_network_connections(void);
|
||||
extern int main_loop(void);
|
||||
extern void terminate_connection(struct connection_t *c, bool report);
|
||||
extern void flush_queue(struct node_t *n);
|
||||
extern bool read_rsa_public_key(struct connection_t *c);
|
||||
extern void send_mtu_probe(struct node_t *n);
|
||||
extern void load_all_subnets(void);
|
||||
extern void tarpit(int fd);
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
#define closesocket(s) close(s)
|
||||
#else
|
||||
extern CRITICAL_SECTION mutex;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
798
src/net_packet.c
Normal file
798
src/net_packet.c
Normal file
|
|
@ -0,0 +1,798 @@
|
|||
/*
|
||||
net_packet.c -- Handles in- and outgoing VPN packets
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2010 Timothy Redaelli <timothy@redaelli.eu>
|
||||
2010 Brandon Black <blblack@gmail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LZO
|
||||
#include LZO1X_H
|
||||
#endif
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
#include "device.h"
|
||||
#include "ethernet.h"
|
||||
#include "event.h"
|
||||
#include "graph.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "protocol.h"
|
||||
#include "process.h"
|
||||
#include "route.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
int keylifetime = 0;
|
||||
int keyexpires = 0;
|
||||
#ifdef HAVE_LZO
|
||||
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
|
||||
#endif
|
||||
|
||||
static void send_udppacket(node_t *, vpn_packet_t *);
|
||||
|
||||
unsigned replaywin = 16;
|
||||
bool localdiscovery = false;
|
||||
|
||||
#define MAX_SEQNO 1073741824
|
||||
|
||||
/* mtuprobes == 1..30: initial discovery, send bursts with 1 second interval
|
||||
mtuprobes == 31: sleep pinginterval seconds
|
||||
mtuprobes == 32: send 1 burst, sleep pingtimeout second
|
||||
mtuprobes == 33: no response from other side, restart PMTU discovery process
|
||||
|
||||
Probes are sent in batches of at least three, with random sizes between the
|
||||
lower and upper boundaries for the MTU thus far discovered.
|
||||
|
||||
After the initial discovery, a fourth packet is added to each batch with a
|
||||
size larger than the currently known PMTU, to test if the PMTU has increased.
|
||||
|
||||
In case local discovery is enabled, another packet is added to each batch,
|
||||
which will be broadcast to the local network.
|
||||
|
||||
*/
|
||||
|
||||
void send_mtu_probe(node_t *n) {
|
||||
vpn_packet_t packet;
|
||||
int len, i;
|
||||
int timeout = 1;
|
||||
|
||||
n->mtuprobes++;
|
||||
n->mtuevent = NULL;
|
||||
|
||||
if(!n->status.reachable || !n->status.validkey) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send MTU probe to unreachable or rekeying node %s (%s)", n->name, n->hostname);
|
||||
n->mtuprobes = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(n->mtuprobes > 32) {
|
||||
if(!n->minmtu) {
|
||||
n->mtuprobes = 31;
|
||||
timeout = pinginterval;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname);
|
||||
n->mtuprobes = 1;
|
||||
n->minmtu = 0;
|
||||
n->maxmtu = MTU;
|
||||
}
|
||||
|
||||
if(n->mtuprobes >= 10 && n->mtuprobes < 32 && !n->minmtu) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname);
|
||||
n->mtuprobes = 31;
|
||||
}
|
||||
|
||||
if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) {
|
||||
if(n->minmtu > n->maxmtu) {
|
||||
n->minmtu = n->maxmtu;
|
||||
} else {
|
||||
n->maxmtu = n->minmtu;
|
||||
}
|
||||
|
||||
n->mtu = n->minmtu;
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Fixing MTU of %s (%s) to %d after %d probes", n->name, n->hostname, n->mtu, n->mtuprobes);
|
||||
n->mtuprobes = 31;
|
||||
}
|
||||
|
||||
if(n->mtuprobes == 31) {
|
||||
timeout = pinginterval;
|
||||
goto end;
|
||||
} else if(n->mtuprobes == 32) {
|
||||
timeout = pingtimeout;
|
||||
}
|
||||
|
||||
for(i = 0; i < 4 + localdiscovery; i++) {
|
||||
if(i == 0) {
|
||||
if(n->mtuprobes < 30 || n->maxmtu + 8 >= MTU) {
|
||||
continue;
|
||||
}
|
||||
|
||||
len = n->maxmtu + 8;
|
||||
} else if(n->maxmtu <= n->minmtu) {
|
||||
len = n->maxmtu;
|
||||
} else {
|
||||
len = n->minmtu + 1 + rand() % (n->maxmtu - n->minmtu);
|
||||
}
|
||||
|
||||
if(len < 64) {
|
||||
len = 64;
|
||||
}
|
||||
|
||||
memset(packet.data, 0, 14);
|
||||
RAND_bytes(packet.data + 14, len - 14);
|
||||
packet.len = len;
|
||||
|
||||
if(i >= 4 && n->mtuprobes <= 10) {
|
||||
packet.priority = -1;
|
||||
} else {
|
||||
packet.priority = 0;
|
||||
}
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname);
|
||||
|
||||
send_udppacket(n, &packet);
|
||||
}
|
||||
|
||||
end:
|
||||
n->mtuevent = new_event();
|
||||
n->mtuevent->handler = (event_handler_t)send_mtu_probe;
|
||||
n->mtuevent->data = n;
|
||||
n->mtuevent->time = now + timeout;
|
||||
event_add(n->mtuevent);
|
||||
}
|
||||
|
||||
void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Got MTU probe length %d from %s (%s)", packet->len, n->name, n->hostname);
|
||||
|
||||
if(!packet->data[0]) {
|
||||
packet->data[0] = 1;
|
||||
send_udppacket(n, packet);
|
||||
} else {
|
||||
if(n->mtuprobes > 30) {
|
||||
if(len == n->maxmtu + 8) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Increase in PMTU to %s (%s) detected, restarting PMTU discovery", n->name, n->hostname);
|
||||
n->maxmtu = MTU;
|
||||
n->mtuprobes = 10;
|
||||
return;
|
||||
}
|
||||
|
||||
if(n->minmtu) {
|
||||
n->mtuprobes = 30;
|
||||
} else {
|
||||
n->mtuprobes = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(len > n->maxmtu) {
|
||||
len = n->maxmtu;
|
||||
}
|
||||
|
||||
if(n->minmtu < len) {
|
||||
n->minmtu = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
|
||||
if(level == 0) {
|
||||
memcpy(dest, source, len);
|
||||
return len;
|
||||
} else if(level == 10) {
|
||||
#ifdef HAVE_LZO
|
||||
lzo_uint lzolen = MAXSIZE;
|
||||
lzo1x_1_compress(source, len, dest, &lzolen, lzo_wrkmem);
|
||||
return lzolen;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} else if(level < 10) {
|
||||
#ifdef HAVE_ZLIB
|
||||
unsigned long destlen = MAXSIZE;
|
||||
|
||||
if(compress2(dest, &destlen, source, len, level) == Z_OK) {
|
||||
return destlen;
|
||||
} else
|
||||
#endif
|
||||
return 0;
|
||||
} else {
|
||||
#ifdef HAVE_LZO
|
||||
lzo_uint lzolen = MAXSIZE;
|
||||
lzo1x_999_compress(source, len, dest, &lzolen, lzo_wrkmem);
|
||||
return lzolen;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static length_t uncompress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level) {
|
||||
if(level == 0) {
|
||||
memcpy(dest, source, len);
|
||||
return len;
|
||||
} else if(level > 9) {
|
||||
#ifdef HAVE_LZO
|
||||
lzo_uint lzolen = MAXSIZE;
|
||||
|
||||
if(lzo1x_decompress_safe(source, len, dest, &lzolen, NULL) == LZO_E_OK) {
|
||||
return lzolen;
|
||||
} else
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
else {
|
||||
unsigned long destlen = MAXSIZE;
|
||||
|
||||
if(uncompress(dest, &destlen, source, len) == Z_OK) {
|
||||
return destlen;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* VPN packet I/O */
|
||||
|
||||
static void receive_packet(node_t *n, vpn_packet_t *packet) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Received packet of %d bytes from %s (%s)",
|
||||
packet->len, n->name, n->hostname);
|
||||
|
||||
route(n, packet);
|
||||
}
|
||||
|
||||
static bool try_mac(const node_t *n, const vpn_packet_t *inpkt) {
|
||||
unsigned char hmac[EVP_MAX_MD_SIZE];
|
||||
|
||||
if(!n->indigest || !n->inmaclength || !n->inkey || inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HMAC(n->indigest, n->inkey, n->inkeylength, (unsigned char *) &inpkt->seqno, inpkt->len - n->inmaclength, (unsigned char *)hmac, NULL);
|
||||
|
||||
return !memcmp_constant_time(hmac, (char *) &inpkt->seqno + inpkt->len - n->inmaclength, n->inmaclength);
|
||||
}
|
||||
|
||||
static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
||||
vpn_packet_t pkt1, pkt2;
|
||||
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
|
||||
int nextpkt = 0;
|
||||
vpn_packet_t *outpkt;
|
||||
int outlen, outpad;
|
||||
unsigned char hmac[EVP_MAX_MD_SIZE];
|
||||
|
||||
if(!n->inkey) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got packet from %s (%s) but he hasn't got our key yet",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check packet length */
|
||||
|
||||
if(inpkt->len < sizeof(inpkt->seqno) + n->inmaclength) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got too short packet from %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check the message authentication code */
|
||||
|
||||
if(n->indigest && n->inmaclength) {
|
||||
inpkt->len -= n->inmaclength;
|
||||
HMAC(n->indigest, n->inkey, n->inkeylength,
|
||||
(unsigned char *) &inpkt->seqno, inpkt->len, (unsigned char *)hmac, NULL);
|
||||
|
||||
if(memcmp_constant_time(hmac, (char *) &inpkt->seqno + inpkt->len, n->inmaclength)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Got unauthenticated packet from %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrypt the packet */
|
||||
|
||||
if(n->incipher) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
|
||||
if(!EVP_DecryptInit_ex(n->inctx, NULL, NULL, NULL, NULL)
|
||||
|| !EVP_DecryptUpdate(n->inctx, (unsigned char *) &outpkt->seqno, &outlen,
|
||||
(unsigned char *) &inpkt->seqno, inpkt->len)
|
||||
|| !EVP_DecryptFinal_ex(n->inctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error decrypting packet from %s (%s): %s",
|
||||
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
return;
|
||||
}
|
||||
|
||||
outpkt->len = outlen + outpad;
|
||||
inpkt = outpkt;
|
||||
}
|
||||
|
||||
/* Check the sequence number */
|
||||
|
||||
inpkt->len -= sizeof(inpkt->seqno);
|
||||
inpkt->seqno = ntohl(inpkt->seqno);
|
||||
|
||||
if(replaywin) {
|
||||
if(inpkt->seqno != n->received_seqno + 1) {
|
||||
if(inpkt->seqno >= n->received_seqno + replaywin * 8) {
|
||||
if(n->farfuture++ < replaywin >> 2) {
|
||||
ifdebug(TRAFFIC) logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
|
||||
n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture);
|
||||
return;
|
||||
}
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_WARNING, "Lost %d packets from %s (%s)",
|
||||
inpkt->seqno - n->received_seqno - 1, n->name, n->hostname);
|
||||
memset(n->late, 0, replaywin);
|
||||
} else if(inpkt->seqno <= n->received_seqno) {
|
||||
if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) {
|
||||
ifdebug(TRAFFIC) logger(LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
|
||||
n->name, n->hostname, inpkt->seqno, n->received_seqno);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
for(uint32_t i = n->received_seqno + 1; i < inpkt->seqno; i++) {
|
||||
n->late[(i / 8) % replaywin] |= 1 << i % 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n->farfuture = 0;
|
||||
n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8);
|
||||
}
|
||||
|
||||
if(inpkt->seqno > n->received_seqno) {
|
||||
n->received_seqno = inpkt->seqno;
|
||||
}
|
||||
|
||||
if(n->received_seqno > MAX_SEQNO) {
|
||||
keyexpires = 0;
|
||||
}
|
||||
|
||||
/* Decompress the packet */
|
||||
|
||||
length_t origlen = inpkt->len;
|
||||
|
||||
if(n->incompression) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
|
||||
if(!(outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression))) {
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while uncompressing packet from %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
inpkt = outpkt;
|
||||
|
||||
origlen -= MTU / 64 + 20;
|
||||
}
|
||||
|
||||
inpkt->priority = 0;
|
||||
|
||||
if(!inpkt->data[12] && !inpkt->data[13]) {
|
||||
mtu_probe_h(n, inpkt, origlen);
|
||||
} else {
|
||||
receive_packet(n, inpkt);
|
||||
}
|
||||
}
|
||||
|
||||
void receive_tcppacket(connection_t *c, const char *buffer, length_t len) {
|
||||
vpn_packet_t outpkt;
|
||||
|
||||
if(len > sizeof(outpkt.data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
outpkt.len = len;
|
||||
|
||||
if(c->options & OPTION_TCPONLY) {
|
||||
outpkt.priority = 0;
|
||||
} else {
|
||||
outpkt.priority = -1;
|
||||
}
|
||||
|
||||
memcpy(outpkt.data, buffer, len);
|
||||
|
||||
receive_packet(c->node, &outpkt);
|
||||
}
|
||||
|
||||
static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
||||
vpn_packet_t pkt1, pkt2;
|
||||
vpn_packet_t *pkt[] = { &pkt1, &pkt2, &pkt1, &pkt2 };
|
||||
vpn_packet_t *inpkt = origpkt;
|
||||
int nextpkt = 0;
|
||||
vpn_packet_t *outpkt;
|
||||
int origlen;
|
||||
int outlen, outpad;
|
||||
int origpriority;
|
||||
|
||||
if(!n->status.reachable) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure we have a valid key */
|
||||
|
||||
if(!n->status.validkey) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO,
|
||||
"No valid key known yet for %s (%s), forwarding via TCP",
|
||||
n->name, n->hostname);
|
||||
|
||||
if(n->last_req_key + 10 <= now) {
|
||||
send_req_key(n);
|
||||
n->last_req_key = now;
|
||||
}
|
||||
|
||||
send_tcppacket(n->nexthop->connection, origpkt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(n->options & OPTION_PMTU_DISCOVERY && inpkt->len > n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO,
|
||||
"Packet for %s (%s) larger than minimum MTU, forwarding via %s",
|
||||
n->name, n->hostname, n != n->nexthop ? n->nexthop->name : "TCP");
|
||||
|
||||
if(n != n->nexthop) {
|
||||
send_packet(n->nexthop, origpkt);
|
||||
} else {
|
||||
send_tcppacket(n->nexthop->connection, origpkt);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
origlen = inpkt->len;
|
||||
origpriority = inpkt->priority;
|
||||
|
||||
/* Compress the packet */
|
||||
|
||||
if(n->outcompression) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
|
||||
if(!(outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression))) {
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while compressing packet to %s (%s)",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
inpkt = outpkt;
|
||||
}
|
||||
|
||||
/* Add sequence number */
|
||||
|
||||
inpkt->seqno = htonl(++(n->sent_seqno));
|
||||
inpkt->len += sizeof(inpkt->seqno);
|
||||
|
||||
/* Encrypt the packet */
|
||||
|
||||
if(n->outcipher) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
|
||||
if(!EVP_EncryptInit_ex(n->outctx, NULL, NULL, NULL, NULL)
|
||||
|| !EVP_EncryptUpdate(n->outctx, (unsigned char *) &outpkt->seqno, &outlen,
|
||||
(unsigned char *) &inpkt->seqno, inpkt->len)
|
||||
|| !EVP_EncryptFinal_ex(n->outctx, (unsigned char *) &outpkt->seqno + outlen, &outpad)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, "Error while encrypting packet to %s (%s): %s",
|
||||
n->name, n->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
goto end;
|
||||
}
|
||||
|
||||
outpkt->len = outlen + outpad;
|
||||
inpkt = outpkt;
|
||||
}
|
||||
|
||||
/* Add the message authentication code */
|
||||
|
||||
if(n->outdigest && n->outmaclength) {
|
||||
HMAC(n->outdigest, n->outkey, n->outkeylength, (unsigned char *) &inpkt->seqno,
|
||||
inpkt->len, (unsigned char *) &inpkt->seqno + inpkt->len, NULL);
|
||||
inpkt->len += n->outmaclength;
|
||||
}
|
||||
|
||||
/* Determine which socket we have to use */
|
||||
|
||||
if(n->address.sa.sa_family != listen_socket[n->sock].sa.sa.sa_family) {
|
||||
for(int sock = 0; sock < listen_sockets; sock++) {
|
||||
if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family) {
|
||||
n->sock = sock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the packet */
|
||||
|
||||
struct sockaddr *sa;
|
||||
socklen_t sl;
|
||||
int sock;
|
||||
sockaddr_t broadcast;
|
||||
|
||||
/* Overloaded use of priority field: -1 means local broadcast */
|
||||
|
||||
if(origpriority == -1 && n->prevedge) {
|
||||
sock = rand() % listen_sockets;
|
||||
memset(&broadcast, 0, sizeof(broadcast));
|
||||
|
||||
if(listen_socket[sock].sa.sa.sa_family == AF_INET6) {
|
||||
broadcast.in6.sin6_family = AF_INET6;
|
||||
broadcast.in6.sin6_addr.s6_addr[0x0] = 0xff;
|
||||
broadcast.in6.sin6_addr.s6_addr[0x1] = 0x02;
|
||||
broadcast.in6.sin6_addr.s6_addr[0xf] = 0x01;
|
||||
broadcast.in6.sin6_port = n->prevedge->address.in.sin_port;
|
||||
broadcast.in6.sin6_scope_id = listen_socket[sock].sa.in6.sin6_scope_id;
|
||||
} else {
|
||||
broadcast.in.sin_family = AF_INET;
|
||||
broadcast.in.sin_addr.s_addr = -1;
|
||||
broadcast.in.sin_port = n->prevedge->address.in.sin_port;
|
||||
}
|
||||
|
||||
sa = &broadcast.sa;
|
||||
sl = SALEN(broadcast.sa);
|
||||
} else {
|
||||
if(origpriority == -1) {
|
||||
origpriority = 0;
|
||||
}
|
||||
|
||||
sa = &(n->address.sa);
|
||||
sl = SALEN(n->address.sa);
|
||||
sock = n->sock;
|
||||
}
|
||||
|
||||
if(priorityinheritance && origpriority != listen_socket[n->sock].priority) {
|
||||
listen_socket[n->sock].priority = origpriority;
|
||||
|
||||
switch(listen_socket[n->sock].sa.sa.sa_family) {
|
||||
#if defined(IP_TOS)
|
||||
|
||||
case AF_INET:
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv4 outgoing packet priority to %d", origpriority);
|
||||
|
||||
if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IP, IP_TOS, (void *)&origpriority, sizeof(origpriority))) { /* SO_PRIORITY doesn't seem to work */
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
#if defined(IPV6_TCLASS)
|
||||
|
||||
case AF_INET6:
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting IPv6 outgoing packet priority to %d", origpriority);
|
||||
|
||||
if(setsockopt(listen_socket[n->sock].udp, IPPROTO_IPV6, IPV6_TCLASS, (void *)&origpriority, sizeof(origpriority))) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno));
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) {
|
||||
if(sockmsgsize(sockerrno)) {
|
||||
if(n->maxmtu >= origlen) {
|
||||
n->maxmtu = origlen - 1;
|
||||
}
|
||||
|
||||
if(n->mtu >= origlen) {
|
||||
n->mtu = origlen - 1;
|
||||
}
|
||||
} else {
|
||||
ifdebug(TRAFFIC) logger(LOG_WARNING, "Error sending packet to %s (%s): %s", n->name, n->hostname, sockstrerror(sockerrno));
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
origpkt->len = origlen;
|
||||
}
|
||||
|
||||
/*
|
||||
send a packet to the given vpn ip.
|
||||
*/
|
||||
void send_packet(const node_t *n, vpn_packet_t *packet) {
|
||||
node_t *via;
|
||||
|
||||
if(n == myself) {
|
||||
if(overwrite_mac) {
|
||||
memcpy(packet->data, mymac.x, ETH_ALEN);
|
||||
}
|
||||
|
||||
devops.write(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, "Sending packet of %d bytes to %s (%s)",
|
||||
packet->len, n->name, n->hostname);
|
||||
|
||||
if(!n->status.reachable) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Node %s (%s) is not reachable",
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
via = (packet->priority == -1 || n->via == myself) ? n->nexthop : n->via;
|
||||
|
||||
if(via != n)
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Sending packet to %s via %s (%s)",
|
||||
n->name, via->name, n->via->hostname);
|
||||
|
||||
if(packet->priority == -1 || ((myself->options | via->options) & OPTION_TCPONLY)) {
|
||||
if(!send_tcppacket(via->connection, packet)) {
|
||||
terminate_connection(via->connection, true);
|
||||
}
|
||||
} else {
|
||||
send_udppacket(via, packet);
|
||||
}
|
||||
}
|
||||
|
||||
/* Broadcast a packet using the minimum spanning tree */
|
||||
|
||||
void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
|
||||
avl_node_t *node;
|
||||
connection_t *c;
|
||||
node_t *n;
|
||||
|
||||
// Always give ourself a copy of the packet.
|
||||
if(from != myself) {
|
||||
send_packet(myself, packet);
|
||||
}
|
||||
|
||||
// In TunnelServer mode, do not forward broadcast packets.
|
||||
// The MST might not be valid and create loops.
|
||||
if(tunnelserver || broadcast_mode == BMODE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
|
||||
packet->len, from->name, from->hostname);
|
||||
|
||||
switch(broadcast_mode) {
|
||||
// In MST mode, broadcast packets travel via the Minimum Spanning Tree.
|
||||
// This guarantees all nodes receive the broadcast packet, and
|
||||
// usually distributes the sending of broadcast packets over all nodes.
|
||||
case BMODE_MST:
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
|
||||
if(c->status.active && c->status.mst && c != from->nexthop->connection) {
|
||||
send_packet(c->node, packet);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// In direct mode, we send copies to each node we know of.
|
||||
// However, this only reaches nodes that can be reached in a single hop.
|
||||
// We don't have enough information to forward broadcast packets in this case.
|
||||
case BMODE_DIRECT:
|
||||
if(from != myself) {
|
||||
break;
|
||||
}
|
||||
|
||||
for(node = node_udp_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
|
||||
if(n->status.reachable && n != myself && ((n->via == myself && n->nexthop == n) || n->via == n)) {
|
||||
send_packet(n, packet);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
|
||||
avl_node_t *node;
|
||||
edge_t *e;
|
||||
node_t *n = NULL;
|
||||
static time_t last_hard_try = 0;
|
||||
|
||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
||||
e = node->data;
|
||||
|
||||
if(e->to == myself) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(last_hard_try == now && sockaddrcmp_noport(from, &e->address)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!try_mac(e->to, pkt)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
n = e->to;
|
||||
break;
|
||||
}
|
||||
|
||||
last_hard_try = now;
|
||||
return n;
|
||||
}
|
||||
|
||||
void handle_incoming_vpn_data(int sock) {
|
||||
vpn_packet_t pkt;
|
||||
char *hostname;
|
||||
sockaddr_t from;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
node_t *n;
|
||||
|
||||
ssize_t len = recvfrom(listen_socket[sock].udp, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
|
||||
|
||||
if(len <= 0 || len > UINT16_MAX) {
|
||||
if(len >= 0) {
|
||||
logger(LOG_ERR, "Receiving packet with invalid size");
|
||||
} else if(!sockwouldblock(sockerrno)) {
|
||||
logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pkt.len = len;
|
||||
sockaddrunmap(&from); /* Some braindead IPv6 implementations do stupid things. */
|
||||
|
||||
n = lookup_node_udp(&from);
|
||||
|
||||
if(!n) {
|
||||
n = try_harder(&from, &pkt);
|
||||
|
||||
if(n) {
|
||||
update_node_udp(n, &from);
|
||||
} else ifdebug(PROTOCOL) {
|
||||
hostname = sockaddr2hostname(&from);
|
||||
logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
|
||||
free(hostname);
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
n->sock = sock;
|
||||
|
||||
receive_udppacket(n, &pkt);
|
||||
}
|
||||
1170
src/net_setup.c
Normal file
1170
src/net_setup.c
Normal file
File diff suppressed because it is too large
Load diff
733
src/net_socket.c
Normal file
733
src/net_socket.c
Normal file
|
|
@ -0,0 +1,733 @@
|
|||
/*
|
||||
net_socket.c -- Handle various kinds of sockets.
|
||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
2009 Florian Forster <octo@verplant.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
#include "event.h"
|
||||
#include "logger.h"
|
||||
#include "meta.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "protocol.h"
|
||||
#include "proxy.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* Needed on Mac OS/X */
|
||||
#ifndef SOL_TCP
|
||||
#define SOL_TCP IPPROTO_TCP
|
||||
#endif
|
||||
|
||||
int addressfamily = AF_UNSPEC;
|
||||
int mintimeout = 0;
|
||||
int maxtimeout = 900;
|
||||
int seconds_till_retry = 5;
|
||||
int udp_rcvbuf = 0;
|
||||
int udp_sndbuf = 0;
|
||||
|
||||
listen_socket_t listen_socket[MAXSOCKETS];
|
||||
int listen_sockets;
|
||||
list_t *outgoing_list = NULL;
|
||||
|
||||
/* Setup sockets */
|
||||
|
||||
static void configure_tcp(connection_t *c) {
|
||||
int option;
|
||||
|
||||
#ifdef O_NONBLOCK
|
||||
int flags = fcntl(c->socket, F_GETFL);
|
||||
|
||||
if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
logger(LOG_ERR, "fcntl for %s: %s", c->hostname, strerror(errno));
|
||||
}
|
||||
|
||||
#elif defined(WIN32)
|
||||
unsigned long arg = 1;
|
||||
|
||||
if(ioctlsocket(c->socket, FIONBIO, &arg) != 0) {
|
||||
logger(LOG_ERR, "ioctlsocket for %s: %s", c->hostname, sockstrerror(sockerrno));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SOL_TCP) && defined(TCP_NODELAY)
|
||||
option = 1;
|
||||
setsockopt(c->socket, SOL_TCP, TCP_NODELAY, (void *)&option, sizeof(option));
|
||||
#endif
|
||||
|
||||
#if defined(IP_TOS) && defined(IPTOS_LOWDELAY)
|
||||
option = IPTOS_LOWDELAY;
|
||||
setsockopt(c->socket, IPPROTO_IP, IP_TOS, (void *)&option, sizeof(option));
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_TCLASS) && defined(IPTOS_LOWDELAY)
|
||||
option = IPTOS_LOWDELAY;
|
||||
setsockopt(c->socket, IPPROTO_IPV6, IPV6_TCLASS, (void *)&option, sizeof(option));
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool bind_to_interface(int sd) {
|
||||
char *iface;
|
||||
|
||||
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
|
||||
struct ifreq ifr;
|
||||
int status;
|
||||
#endif /* defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) */
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, iface, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = 0;
|
||||
free(iface);
|
||||
|
||||
status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr));
|
||||
|
||||
if(status) {
|
||||
logger(LOG_ERR, "Can't bind to interface %s: %s", ifr.ifr_name, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
#else /* if !defined(SOL_SOCKET) || !defined(SO_BINDTODEVICE) */
|
||||
logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int setup_listen_socket(const sockaddr_t *sa) {
|
||||
int nfd;
|
||||
char *addrstr;
|
||||
int option;
|
||||
char *iface;
|
||||
|
||||
nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
if(nfd < 0) {
|
||||
ifdebug(STATUS) logger(LOG_ERR, "Creating metasocket failed: %s", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(nfd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
/* Optimize TCP settings */
|
||||
|
||||
option = 1;
|
||||
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
|
||||
|
||||
#if defined(IPV6_V6ONLY)
|
||||
|
||||
if(sa->sa.sa_family == AF_INET6) {
|
||||
setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
|
||||
}
|
||||
|
||||
#else
|
||||
#warning IPV6_V6ONLY not defined
|
||||
#endif
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) {
|
||||
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, iface, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = 0;
|
||||
free(iface);
|
||||
|
||||
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr))) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "Can't bind to interface %s: %s", ifr.ifr_name, strerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
logger(LOG_WARNING, "%s not supported on this platform", "BindToInterface");
|
||||
#endif
|
||||
}
|
||||
|
||||
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
|
||||
closesocket(nfd);
|
||||
addrstr = sockaddr2hostname(sa);
|
||||
logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, sockstrerror(sockerrno));
|
||||
free(addrstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(listen(nfd, 3)) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "listen", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nfd;
|
||||
}
|
||||
|
||||
int setup_vpn_in_socket(const sockaddr_t *sa) {
|
||||
int nfd;
|
||||
char *addrstr;
|
||||
int option;
|
||||
|
||||
nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if(nfd < 0) {
|
||||
logger(LOG_ERR, "Creating UDP socket failed: %s", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(nfd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
#ifdef O_NONBLOCK
|
||||
{
|
||||
int flags = fcntl(nfd, F_GETFL);
|
||||
|
||||
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "fcntl",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#elif defined(WIN32)
|
||||
{
|
||||
unsigned long arg = 1;
|
||||
|
||||
if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
option = 1;
|
||||
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));
|
||||
setsockopt(nfd, SOL_SOCKET, SO_BROADCAST, (void *)&option, sizeof(option));
|
||||
|
||||
if(udp_rcvbuf && setsockopt(nfd, SOL_SOCKET, SO_RCVBUF, (void *)&udp_rcvbuf, sizeof(udp_rcvbuf))) {
|
||||
logger(LOG_WARNING, "Can't set UDP SO_RCVBUF to %i: %s", udp_rcvbuf, strerror(errno));
|
||||
}
|
||||
|
||||
if(udp_sndbuf && setsockopt(nfd, SOL_SOCKET, SO_SNDBUF, (void *)&udp_sndbuf, sizeof(udp_sndbuf))) {
|
||||
logger(LOG_WARNING, "Can't set UDP SO_SNDBUF to %i: %s", udp_sndbuf, strerror(errno));
|
||||
}
|
||||
|
||||
#if defined(IPV6_V6ONLY)
|
||||
|
||||
if(sa->sa.sa_family == AF_INET6) {
|
||||
setsockopt(nfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(IP_DONTFRAG) && !defined(IP_DONTFRAGMENT)
|
||||
#define IP_DONTFRAGMENT IP_DONTFRAG
|
||||
#endif
|
||||
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
|
||||
|
||||
if(myself->options & OPTION_PMTU_DISCOVERY) {
|
||||
option = IP_PMTUDISC_DO;
|
||||
setsockopt(nfd, IPPROTO_IP, IP_MTU_DISCOVER, (void *)&option, sizeof(option));
|
||||
}
|
||||
|
||||
#elif defined(IP_DONTFRAGMENT)
|
||||
|
||||
if(myself->options & OPTION_PMTU_DISCOVERY) {
|
||||
option = 1;
|
||||
setsockopt(nfd, IPPROTO_IP, IP_DONTFRAGMENT, (void *)&option, sizeof(option));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
|
||||
|
||||
if(myself->options & OPTION_PMTU_DISCOVERY) {
|
||||
option = IPV6_PMTUDISC_DO;
|
||||
setsockopt(nfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, (void *)&option, sizeof(option));
|
||||
}
|
||||
|
||||
#elif defined(IPV6_DONTFRAG)
|
||||
|
||||
if(myself->options & OPTION_PMTU_DISCOVERY) {
|
||||
option = 1;
|
||||
setsockopt(nfd, IPPROTO_IPV6, IPV6_DONTFRAG, (void *)&option, sizeof(option));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(!bind_to_interface(nfd)) {
|
||||
closesocket(nfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
|
||||
closesocket(nfd);
|
||||
addrstr = sockaddr2hostname(sa);
|
||||
logger(LOG_ERR, "Can't bind to %s/udp: %s", addrstr, sockstrerror(sockerrno));
|
||||
free(addrstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nfd;
|
||||
} /* int setup_vpn_in_socket */
|
||||
|
||||
void retry_outgoing(outgoing_t *outgoing) {
|
||||
outgoing->timeout += 5;
|
||||
|
||||
if(outgoing->timeout < mintimeout) {
|
||||
outgoing->timeout = mintimeout;
|
||||
}
|
||||
|
||||
if(outgoing->timeout > maxtimeout) {
|
||||
outgoing->timeout = maxtimeout;
|
||||
}
|
||||
|
||||
if(outgoing->event) {
|
||||
event_del(outgoing->event);
|
||||
}
|
||||
|
||||
outgoing->event = new_event();
|
||||
outgoing->event->handler = (event_handler_t) setup_outgoing_connection;
|
||||
outgoing->event->time = now + outgoing->timeout;
|
||||
outgoing->event->data = outgoing;
|
||||
event_add(outgoing->event);
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE,
|
||||
"Trying to re-establish outgoing connection in %d seconds",
|
||||
outgoing->timeout);
|
||||
}
|
||||
|
||||
void finish_connecting(connection_t *c) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
|
||||
|
||||
c->last_ping_time = now;
|
||||
|
||||
send_id(c);
|
||||
}
|
||||
|
||||
static void do_outgoing_pipe(connection_t *c, char *command) {
|
||||
#ifndef HAVE_MINGW
|
||||
int fd[2];
|
||||
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
|
||||
logger(LOG_ERR, "Could not create socketpair: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if(fork()) {
|
||||
c->socket = fd[0];
|
||||
close(fd[1]);
|
||||
ifdebug(CONNECTIONS) logger(LOG_DEBUG, "Using proxy %s", command);
|
||||
return;
|
||||
}
|
||||
|
||||
close(0);
|
||||
close(1);
|
||||
close(fd[0]);
|
||||
dup2(fd[1], 0);
|
||||
dup2(fd[1], 1);
|
||||
close(fd[1]);
|
||||
|
||||
// Other filedescriptors should be closed automatically by CLOEXEC
|
||||
|
||||
char *host = NULL;
|
||||
char *port = NULL;
|
||||
|
||||
sockaddr2str(&c->address, &host, &port);
|
||||
setenv("REMOTEADDRESS", host, true);
|
||||
setenv("REMOTEPORT", port, true);
|
||||
setenv("NODE", c->name, true);
|
||||
setenv("NAME", myself->name, true);
|
||||
|
||||
if(netname) {
|
||||
setenv("NETNAME", netname, true);
|
||||
}
|
||||
|
||||
int result = system(command);
|
||||
|
||||
if(result < 0) {
|
||||
logger(LOG_ERR, "Could not execute %s: %s\n", command, strerror(errno));
|
||||
} else if(result) {
|
||||
logger(LOG_ERR, "%s exited with non-zero status %d", command, result);
|
||||
}
|
||||
|
||||
exit(result);
|
||||
#else
|
||||
logger(LOG_ERR, "Proxy type exec not supported on this platform!");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_valid_host_port(const char *host, const char *port) {
|
||||
for(const char *p = host; *p; p++)
|
||||
if(!isalnum(*p) && *p != '-' && *p != '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(const char *p = port; *p; p++)
|
||||
if(!isalnum(*p)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void do_outgoing_connection(connection_t *c) {
|
||||
struct addrinfo *proxyai = NULL;
|
||||
int result;
|
||||
|
||||
if(!c->outgoing) {
|
||||
logger(LOG_ERR, "do_outgoing_connection() for %s called without c->outgoing", c->name);
|
||||
abort();
|
||||
}
|
||||
|
||||
begin:
|
||||
|
||||
if(!c->outgoing->ai) {
|
||||
if(!c->outgoing->cfg) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "Could not set up a meta connection to %s",
|
||||
c->name);
|
||||
c->status.remove = true;
|
||||
retry_outgoing(c->outgoing);
|
||||
c->outgoing = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
char *address, *port, *space;
|
||||
|
||||
get_config_string(c->outgoing->cfg, &address);
|
||||
|
||||
space = strchr(address, ' ');
|
||||
|
||||
if(space) {
|
||||
port = xstrdup(space + 1);
|
||||
*space = 0;
|
||||
} else {
|
||||
if(!get_config_string(lookup_config(c->config_tree, "Port"), &port)) {
|
||||
port = xstrdup("655");
|
||||
}
|
||||
}
|
||||
|
||||
c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
|
||||
|
||||
// If we cannot resolve the address, maybe we are using a proxy that can?
|
||||
if(!c->outgoing->ai && proxytype != PROXY_NONE && is_valid_host_port(address, port)) {
|
||||
memset(&c->address, 0, sizeof(c->address));
|
||||
c->address.sa.sa_family = AF_UNKNOWN;
|
||||
c->address.unknown.address = address;
|
||||
c->address.unknown.port = port;
|
||||
} else {
|
||||
free(address);
|
||||
free(port);
|
||||
}
|
||||
|
||||
c->outgoing->aip = c->outgoing->ai;
|
||||
c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg);
|
||||
|
||||
if(!c->outgoing->ai && proxytype != PROXY_NONE) {
|
||||
goto connect;
|
||||
}
|
||||
}
|
||||
|
||||
if(!c->outgoing->aip) {
|
||||
if(c->outgoing->ai) {
|
||||
freeaddrinfo(c->outgoing->ai);
|
||||
}
|
||||
|
||||
c->outgoing->ai = NULL;
|
||||
goto begin;
|
||||
}
|
||||
|
||||
memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen);
|
||||
c->outgoing->aip = c->outgoing->aip->ai_next;
|
||||
|
||||
connect:
|
||||
|
||||
if(c->hostname) {
|
||||
free(c->hostname);
|
||||
}
|
||||
|
||||
c->hostname = sockaddr2hostname(&c->address);
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "Trying to connect to %s (%s)", c->name,
|
||||
c->hostname);
|
||||
|
||||
if(!proxytype) {
|
||||
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
} else if(proxytype == PROXY_EXEC) {
|
||||
c->status.proxy_passed = true;
|
||||
do_outgoing_pipe(c, proxyhost);
|
||||
} else {
|
||||
proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM);
|
||||
|
||||
if(!proxyai) {
|
||||
goto begin;
|
||||
}
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "Using proxy at %s port %s", proxyhost, proxyport);
|
||||
c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
|
||||
if(c->socket == -1) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
|
||||
goto begin;
|
||||
}
|
||||
|
||||
if(proxytype != PROXY_EXEC) {
|
||||
configure_tcp(c);
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(c->socket, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
if(proxytype != PROXY_EXEC) {
|
||||
#if defined(IPV6_V6ONLY)
|
||||
int option = 1;
|
||||
|
||||
if(c->address.sa.sa_family == AF_INET6) {
|
||||
setsockopt(c->socket, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&option, sizeof(option));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bind_to_interface(c->socket);
|
||||
|
||||
int b = -1;
|
||||
|
||||
for(int i = 0; i < listen_sockets; i++) {
|
||||
if(listen_socket[i].sa.sa.sa_family == c->address.sa.sa_family) {
|
||||
if(b == -1) {
|
||||
b = i;
|
||||
} else {
|
||||
b = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(b != -1) {
|
||||
sockaddr_t sa = listen_socket[b].sa;
|
||||
|
||||
if(sa.sa.sa_family == AF_INET) {
|
||||
sa.in.sin_port = 0;
|
||||
} else if(sa.sa.sa_family == AF_INET6) {
|
||||
sa.in6.sin6_port = 0;
|
||||
}
|
||||
|
||||
if(bind(c->socket, &sa.sa, SALEN(sa.sa))) {
|
||||
char *addrstr = sockaddr2hostname(&sa);
|
||||
logger(LOG_ERR, "Can't bind to %s/tcp: %s", addrstr, sockstrerror(sockerrno));
|
||||
free(addrstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Connect */
|
||||
|
||||
if(!proxytype) {
|
||||
result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
|
||||
} else if(proxytype == PROXY_EXEC) {
|
||||
result = 0;
|
||||
} else {
|
||||
result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen);
|
||||
freeaddrinfo(proxyai);
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
if(result == -1) {
|
||||
if(sockinprogress(sockerrno)) {
|
||||
c->last_ping_time = now;
|
||||
c->status.connecting = true;
|
||||
return;
|
||||
}
|
||||
|
||||
closesocket(c->socket);
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "%s: %s", c->hostname, sockstrerror(sockerrno));
|
||||
|
||||
goto begin;
|
||||
}
|
||||
|
||||
finish_connecting(c);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void setup_outgoing_connection(outgoing_t *outgoing) {
|
||||
connection_t *c;
|
||||
node_t *n;
|
||||
|
||||
outgoing->event = NULL;
|
||||
|
||||
n = lookup_node(outgoing->name);
|
||||
|
||||
if(n)
|
||||
if(n->connection) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "Already connected to %s", outgoing->name);
|
||||
|
||||
n->connection->outgoing = outgoing;
|
||||
return;
|
||||
}
|
||||
|
||||
c = new_connection();
|
||||
c->name = xstrdup(outgoing->name);
|
||||
c->outcipher = myself->connection->outcipher;
|
||||
c->outdigest = myself->connection->outdigest;
|
||||
c->outmaclength = myself->connection->outmaclength;
|
||||
c->outcompression = myself->connection->outcompression;
|
||||
|
||||
init_configuration(&c->config_tree);
|
||||
|
||||
if(!read_connection_config(c)) {
|
||||
free_connection(c);
|
||||
outgoing->timeout = maxtimeout;
|
||||
retry_outgoing(outgoing);
|
||||
return;
|
||||
}
|
||||
|
||||
outgoing->cfg = lookup_config(c->config_tree, "Address");
|
||||
|
||||
if(!outgoing->cfg) {
|
||||
logger(LOG_ERR, "No address specified for %s", c->name);
|
||||
free_connection(c);
|
||||
outgoing->timeout = maxtimeout;
|
||||
retry_outgoing(outgoing);
|
||||
return;
|
||||
}
|
||||
|
||||
c->outgoing = outgoing;
|
||||
c->last_ping_time = now;
|
||||
|
||||
connection_add(c);
|
||||
|
||||
do_outgoing_connection(c);
|
||||
}
|
||||
|
||||
/*
|
||||
accept a new tcp connect and create a
|
||||
new connection
|
||||
*/
|
||||
bool handle_new_meta_connection(int sock) {
|
||||
static const int max_accept_burst = 10;
|
||||
static int last_accept_burst;
|
||||
static int last_accept_time;
|
||||
connection_t *c;
|
||||
sockaddr_t sa;
|
||||
int fd;
|
||||
socklen_t len = sizeof(sa);
|
||||
|
||||
fd = accept(sock, &sa.sa, &len);
|
||||
|
||||
if(fd < 0) {
|
||||
logger(LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(last_accept_time == now) {
|
||||
last_accept_burst++;
|
||||
|
||||
if(last_accept_burst >= max_accept_burst) {
|
||||
if(last_accept_burst == max_accept_burst) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_WARNING, "Throttling incoming connections");
|
||||
}
|
||||
|
||||
tarpit(fd);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
last_accept_burst = 0;
|
||||
last_accept_time = now;
|
||||
}
|
||||
|
||||
sockaddrunmap(&sa);
|
||||
|
||||
c = new_connection();
|
||||
c->name = xstrdup("<unknown>");
|
||||
c->outcipher = myself->connection->outcipher;
|
||||
c->outdigest = myself->connection->outdigest;
|
||||
c->outmaclength = myself->connection->outmaclength;
|
||||
c->outcompression = myself->connection->outcompression;
|
||||
|
||||
c->address = sa;
|
||||
c->hostname = sockaddr2hostname(&sa);
|
||||
c->socket = fd;
|
||||
c->last_ping_time = now;
|
||||
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection from %s", c->hostname);
|
||||
|
||||
configure_tcp(c);
|
||||
|
||||
connection_add(c);
|
||||
|
||||
c->allow_request = ID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void free_outgoing(outgoing_t *outgoing) {
|
||||
if(outgoing->ai) {
|
||||
freeaddrinfo(outgoing->ai);
|
||||
}
|
||||
|
||||
if(outgoing->name) {
|
||||
free(outgoing->name);
|
||||
}
|
||||
|
||||
free(outgoing);
|
||||
}
|
||||
|
||||
void try_outgoing_connections(void) {
|
||||
static config_t *cfg = NULL;
|
||||
char *name;
|
||||
outgoing_t *outgoing;
|
||||
|
||||
outgoing_list = list_alloc((list_action_t)free_outgoing);
|
||||
|
||||
for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
get_config_string(cfg, &name);
|
||||
|
||||
if(!check_id(name)) {
|
||||
logger(LOG_ERR,
|
||||
"Invalid name for outgoing connection in %s line %d",
|
||||
cfg->file, cfg->line);
|
||||
free(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
outgoing = xmalloc_and_zero(sizeof(*outgoing));
|
||||
outgoing->name = name;
|
||||
list_insert_tail(outgoing_list, outgoing);
|
||||
setup_outgoing_connection(outgoing);
|
||||
}
|
||||
}
|
||||
347
src/netutl.c
Normal file
347
src/netutl.c
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
netutl.c -- some supporting network utility code
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
bool hostnames = false;
|
||||
|
||||
/*
|
||||
Turn a string into a struct addrinfo.
|
||||
Return NULL on failure.
|
||||
*/
|
||||
struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype) {
|
||||
struct addrinfo *ai = NULL, hint = {0};
|
||||
int err;
|
||||
|
||||
hint.ai_family = addressfamily;
|
||||
hint.ai_socktype = socktype;
|
||||
|
||||
#if HAVE_DECL_RES_INIT
|
||||
// ensure glibc reloads /etc/resolv.conf.
|
||||
res_init();
|
||||
#endif
|
||||
err = getaddrinfo(address, service, &hint, &ai);
|
||||
|
||||
if(err) {
|
||||
logger(LOG_WARNING, "Error looking up %s port %s: %s", address,
|
||||
service, gai_strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
sockaddr_t str2sockaddr(const char *address, const char *port) {
|
||||
struct addrinfo *ai = NULL, hint = {0};
|
||||
sockaddr_t result;
|
||||
int err;
|
||||
|
||||
hint.ai_family = AF_UNSPEC;
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
err = getaddrinfo(address, port, &hint, &ai);
|
||||
|
||||
if(err || !ai) {
|
||||
ifdebug(SCARY_THINGS)
|
||||
logger(LOG_DEBUG, "Unknown type address %s port %s", address, port);
|
||||
result.sa.sa_family = AF_UNKNOWN;
|
||||
result.unknown.address = xstrdup(address);
|
||||
result.unknown.port = xstrdup(port);
|
||||
return result;
|
||||
}
|
||||
|
||||
memcpy(&result, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
|
||||
char address[NI_MAXHOST];
|
||||
char port[NI_MAXSERV];
|
||||
char *scopeid;
|
||||
int err;
|
||||
|
||||
if(sa->sa.sa_family == AF_UNKNOWN) {
|
||||
if(addrstr) {
|
||||
*addrstr = xstrdup(sa->unknown.address);
|
||||
}
|
||||
|
||||
if(portstr) {
|
||||
*portstr = xstrdup(sa->unknown.port);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
if(err) {
|
||||
logger(LOG_ERR, "Error while translating addresses: %s",
|
||||
gai_strerror(err));
|
||||
abort();
|
||||
}
|
||||
|
||||
scopeid = strchr(address, '%');
|
||||
|
||||
if(scopeid) {
|
||||
*scopeid = '\0'; /* Descope. */
|
||||
}
|
||||
|
||||
if(addrstr) {
|
||||
*addrstr = xstrdup(address);
|
||||
}
|
||||
|
||||
if(portstr) {
|
||||
*portstr = xstrdup(port);
|
||||
}
|
||||
}
|
||||
|
||||
char *sockaddr2hostname(const sockaddr_t *sa) {
|
||||
char *str;
|
||||
char address[NI_MAXHOST] = "unknown";
|
||||
char port[NI_MAXSERV] = "unknown";
|
||||
int err;
|
||||
|
||||
if(sa->sa.sa_family == AF_UNKNOWN) {
|
||||
xasprintf(&str, "%s port %s", sa->unknown.address, sa->unknown.port);
|
||||
return str;
|
||||
}
|
||||
|
||||
err = getnameinfo(&sa->sa, SALEN(sa->sa), address, sizeof(address), port, sizeof(port),
|
||||
hostnames ? 0 : (NI_NUMERICHOST | NI_NUMERICSERV));
|
||||
|
||||
if(err) {
|
||||
logger(LOG_ERR, "Error while looking up hostname: %s",
|
||||
gai_strerror(err));
|
||||
}
|
||||
|
||||
xasprintf(&str, "%s port %s", address, port);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b) {
|
||||
int result;
|
||||
|
||||
result = a->sa.sa_family - b->sa.sa_family;
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
switch(a->sa.sa_family) {
|
||||
case AF_UNSPEC:
|
||||
return 0;
|
||||
|
||||
case AF_UNKNOWN:
|
||||
return strcmp(a->unknown.address, b->unknown.address);
|
||||
|
||||
case AF_INET:
|
||||
return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
|
||||
|
||||
case AF_INET6:
|
||||
return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
|
||||
|
||||
default:
|
||||
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exiting!",
|
||||
a->sa.sa_family);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b) {
|
||||
int result;
|
||||
|
||||
result = a->sa.sa_family - b->sa.sa_family;
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
switch(a->sa.sa_family) {
|
||||
case AF_UNSPEC:
|
||||
return 0;
|
||||
|
||||
case AF_UNKNOWN:
|
||||
result = strcmp(a->unknown.address, b->unknown.address);
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return strcmp(a->unknown.port, b->unknown.port);
|
||||
|
||||
case AF_INET:
|
||||
result = memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return memcmp(&a->in.sin_port, &b->in.sin_port, sizeof(a->in.sin_port));
|
||||
|
||||
case AF_INET6:
|
||||
result = memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return memcmp(&a->in6.sin6_port, &b->in6.sin6_port, sizeof(a->in6.sin6_port));
|
||||
|
||||
default:
|
||||
logger(LOG_ERR, "sockaddrcmp() was called with unknown address family %d, exiting!",
|
||||
a->sa.sa_family);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void sockaddrcpy(sockaddr_t *a, const sockaddr_t *b) {
|
||||
if(b->sa.sa_family != AF_UNKNOWN) {
|
||||
*a = *b;
|
||||
} else {
|
||||
a->unknown.family = AF_UNKNOWN;
|
||||
a->unknown.address = xstrdup(b->unknown.address);
|
||||
a->unknown.port = xstrdup(b->unknown.port);
|
||||
}
|
||||
}
|
||||
|
||||
void sockaddrfree(sockaddr_t *a) {
|
||||
if(a->sa.sa_family == AF_UNKNOWN) {
|
||||
free(a->unknown.address);
|
||||
free(a->unknown.port);
|
||||
}
|
||||
}
|
||||
|
||||
void sockaddrunmap(sockaddr_t *sa) {
|
||||
if(sa->sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr)) {
|
||||
sa->in.sin_addr.s_addr = ((uint32_t *) & sa->in6.sin6_addr)[3];
|
||||
sa->in.sin_family = AF_INET;
|
||||
}
|
||||
}
|
||||
|
||||
void sockaddr_setport(sockaddr_t *sa, const char *port) {
|
||||
uint16_t portnum = htons(atoi(port));
|
||||
|
||||
if(!portnum) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch(sa->sa.sa_family) {
|
||||
case AF_INET:
|
||||
sa->in.sin_port = portnum;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
sa->in6.sin6_port = portnum;
|
||||
break;
|
||||
|
||||
case AF_UNKNOWN:
|
||||
free(sa->unknown.port);
|
||||
sa->unknown.port = xstrdup(port);
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Subnet mask handling */
|
||||
|
||||
int maskcmp(const void *va, const void *vb, int masklen) {
|
||||
int i, m, result;
|
||||
const char *a = va;
|
||||
const char *b = vb;
|
||||
|
||||
for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
|
||||
result = a[i] - b[i];
|
||||
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if(m)
|
||||
return (a[i] & (0x100 - (1 << (8 - m)))) -
|
||||
(b[i] & (0x100 - (1 << (8 - m))));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mask(void *va, int masklen, int len) {
|
||||
int i;
|
||||
char *a = va;
|
||||
|
||||
i = masklen / 8;
|
||||
masklen %= 8;
|
||||
|
||||
if(masklen) {
|
||||
a[i++] &= (0x100 - (1 << (8 - masklen)));
|
||||
}
|
||||
|
||||
for(; i < len; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void maskcpy(void *va, const void *vb, int masklen, int len) {
|
||||
int i, m;
|
||||
char *a = va;
|
||||
const char *b = vb;
|
||||
|
||||
for(m = masklen, i = 0; m >= 8; m -= 8, i++) {
|
||||
a[i] = b[i];
|
||||
}
|
||||
|
||||
if(m) {
|
||||
a[i] = b[i] & (0x100 - (1 << (8 - m)));
|
||||
i++;
|
||||
}
|
||||
|
||||
for(; i < len; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool maskcheck(const void *va, int masklen, int len) {
|
||||
int i;
|
||||
const char *a = va;
|
||||
|
||||
i = masklen / 8;
|
||||
masklen %= 8;
|
||||
|
||||
if(masklen && a[i++] & (0xff >> masklen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(; i < len; i++)
|
||||
if(a[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
43
src/netutl.h
Normal file
43
src/netutl.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef TINC_NETUTL_H
|
||||
#define TINC_NETUTL_H
|
||||
|
||||
/*
|
||||
netutl.h -- header file for netutl.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
|
||||
extern bool hostnames;
|
||||
|
||||
extern struct addrinfo *str2addrinfo(const char *address, const char *service, int socktype);
|
||||
extern sockaddr_t str2sockaddr(const char *address, const char *port);
|
||||
extern void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr);
|
||||
extern char *sockaddr2hostname(const sockaddr_t *sa);
|
||||
extern int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b);
|
||||
extern int sockaddrcmp_noport(const sockaddr_t *a, const sockaddr_t *b);
|
||||
extern void sockaddrunmap(sockaddr_t *sa);
|
||||
extern void sockaddrfree(sockaddr_t *sa);
|
||||
extern void sockaddrcpy(sockaddr_t *dest, const sockaddr_t *src);
|
||||
extern void sockaddr_setport(sockaddr_t *sa, const char *port);
|
||||
extern int maskcmp(const void *a, const void *b, int masklen);
|
||||
extern void maskcpy(void *dest, const void *src, int masklen, int len);
|
||||
extern void mask(void *mask, int masklen, int len);
|
||||
extern bool maskcheck(const void *mask, int masklen, int len);
|
||||
|
||||
#endif
|
||||
199
src/node.c
Normal file
199
src/node.c
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
node.c -- node tree management
|
||||
Copyright (C) 2001-2016 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "node.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
avl_tree_t *node_tree; /* Known nodes, sorted by name */
|
||||
avl_tree_t *node_udp_tree; /* Known nodes, sorted by address and port */
|
||||
|
||||
node_t *myself;
|
||||
|
||||
static int node_compare(const node_t *a, const node_t *b) {
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
static int node_udp_compare(const node_t *a, const node_t *b) {
|
||||
return sockaddrcmp(&a->address, &b->address);
|
||||
}
|
||||
|
||||
void init_nodes(void) {
|
||||
node_tree = avl_alloc_tree((avl_compare_t) node_compare, (avl_action_t) free_node);
|
||||
node_udp_tree = avl_alloc_tree((avl_compare_t) node_udp_compare, NULL);
|
||||
}
|
||||
|
||||
void exit_nodes(void) {
|
||||
avl_delete_tree(node_udp_tree);
|
||||
avl_delete_tree(node_tree);
|
||||
}
|
||||
|
||||
node_t *new_node(void) {
|
||||
node_t *n = xmalloc_and_zero(sizeof(*n));
|
||||
|
||||
if(replaywin) {
|
||||
n->late = xmalloc_and_zero(replaywin);
|
||||
}
|
||||
|
||||
n->subnet_tree = new_subnet_tree();
|
||||
n->edge_tree = new_edge_tree();
|
||||
n->inctx = EVP_CIPHER_CTX_new();
|
||||
n->outctx = EVP_CIPHER_CTX_new();
|
||||
|
||||
if(!n->inctx || !n->outctx) {
|
||||
abort();
|
||||
}
|
||||
|
||||
n->mtu = MTU;
|
||||
n->maxmtu = MTU;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void free_node(node_t *n) {
|
||||
if(n->inkey) {
|
||||
free(n->inkey);
|
||||
}
|
||||
|
||||
if(n->outkey) {
|
||||
free(n->outkey);
|
||||
}
|
||||
|
||||
if(n->subnet_tree) {
|
||||
free_subnet_tree(n->subnet_tree);
|
||||
}
|
||||
|
||||
if(n->edge_tree) {
|
||||
free_edge_tree(n->edge_tree);
|
||||
}
|
||||
|
||||
sockaddrfree(&n->address);
|
||||
|
||||
EVP_CIPHER_CTX_free(n->outctx);
|
||||
EVP_CIPHER_CTX_free(n->inctx);
|
||||
|
||||
if(n->mtuevent) {
|
||||
event_del(n->mtuevent);
|
||||
}
|
||||
|
||||
if(n->hostname) {
|
||||
free(n->hostname);
|
||||
}
|
||||
|
||||
if(n->name) {
|
||||
free(n->name);
|
||||
}
|
||||
|
||||
if(n->late) {
|
||||
free(n->late);
|
||||
}
|
||||
|
||||
free(n);
|
||||
}
|
||||
|
||||
void node_add(node_t *n) {
|
||||
avl_insert(node_tree, n);
|
||||
}
|
||||
|
||||
void node_del(node_t *n) {
|
||||
avl_node_t *node, *next;
|
||||
edge_t *e;
|
||||
subnet_t *s;
|
||||
|
||||
for(node = n->subnet_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
s = node->data;
|
||||
subnet_del(n, s);
|
||||
}
|
||||
|
||||
for(node = n->edge_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
e = node->data;
|
||||
edge_del(e);
|
||||
}
|
||||
|
||||
avl_delete(node_udp_tree, n);
|
||||
avl_delete(node_tree, n);
|
||||
}
|
||||
|
||||
node_t *lookup_node(char *name) {
|
||||
node_t n = {0};
|
||||
|
||||
n.name = name;
|
||||
|
||||
return avl_search(node_tree, &n);
|
||||
}
|
||||
|
||||
node_t *lookup_node_udp(const sockaddr_t *sa) {
|
||||
node_t n = {0};
|
||||
|
||||
n.address = *sa;
|
||||
n.name = NULL;
|
||||
|
||||
return avl_search(node_udp_tree, &n);
|
||||
}
|
||||
|
||||
void update_node_udp(node_t *n, const sockaddr_t *sa) {
|
||||
if(n == myself) {
|
||||
logger(LOG_WARNING, "Trying to update UDP address of myself!");
|
||||
return;
|
||||
}
|
||||
|
||||
avl_delete(node_udp_tree, n);
|
||||
|
||||
if(n->hostname) {
|
||||
free(n->hostname);
|
||||
}
|
||||
|
||||
if(sa) {
|
||||
n->address = *sa;
|
||||
n->hostname = sockaddr2hostname(&n->address);
|
||||
avl_insert(node_udp_tree, n);
|
||||
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
|
||||
} else {
|
||||
memset(&n->address, 0, sizeof(n->address));
|
||||
n->hostname = NULL;
|
||||
ifdebug(PROTOCOL) logger(LOG_DEBUG, "UDP address of %s cleared", n->name);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_nodes(void) {
|
||||
avl_node_t *node;
|
||||
node_t *n;
|
||||
|
||||
logger(LOG_DEBUG, "Nodes:");
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
logger(LOG_DEBUG, " %s at %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s pmtu %d (min %d max %d)",
|
||||
n->name, n->hostname, n->outcipher ? EVP_CIPHER_nid(n->outcipher) : 0,
|
||||
n->outdigest ? EVP_MD_type(n->outdigest) : 0, n->outmaclength, n->outcompression,
|
||||
n->options, bitfield_to_int(&n->status, sizeof(n->status)), n->nexthop ? n->nexthop->name : "-",
|
||||
n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu);
|
||||
}
|
||||
|
||||
logger(LOG_DEBUG, "End of nodes.");
|
||||
}
|
||||
106
src/node.h
Normal file
106
src/node.h
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#ifndef TINC_NODE_H
|
||||
#define TINC_NODE_H
|
||||
|
||||
/*
|
||||
node.h -- header for node.c
|
||||
Copyright (C) 2001-2016 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "connection.h"
|
||||
#include "event.h"
|
||||
#include "subnet.h"
|
||||
|
||||
typedef struct node_status_t {
|
||||
unsigned int unused_active: 1; /* 1 if active (not used for nodes) */
|
||||
unsigned int validkey: 1; /* 1 if we currently have a valid key for him */
|
||||
unsigned int unused_waitingforkey: 1; /* 1 if we already sent out a request */
|
||||
unsigned int visited: 1; /* 1 if this node has been visited by one of the graph algorithms */
|
||||
unsigned int reachable: 1; /* 1 if this node is reachable in the graph */
|
||||
unsigned int indirect: 1; /* 1 if this node is not directly reachable by us */
|
||||
unsigned int unused: 26;
|
||||
} node_status_t;
|
||||
|
||||
typedef struct node_t {
|
||||
char *name; /* name of this node */
|
||||
uint32_t options; /* options turned on for this node */
|
||||
|
||||
int sock; /* Socket to use for outgoing UDP packets */
|
||||
sockaddr_t address; /* his real (internet) ip to send UDP packets to */
|
||||
char *hostname; /* the hostname of its real ip */
|
||||
|
||||
node_status_t status;
|
||||
time_t last_req_key;
|
||||
|
||||
const EVP_CIPHER *incipher; /* Cipher type for UDP packets received from him */
|
||||
char *inkey; /* Cipher key and iv */
|
||||
int inkeylength; /* Cipher key and iv length */
|
||||
EVP_CIPHER_CTX *inctx; /* Cipher context */
|
||||
|
||||
const EVP_CIPHER *outcipher; /* Cipher type for UDP packets sent to him*/
|
||||
char *outkey; /* Cipher key and iv */
|
||||
int outkeylength; /* Cipher key and iv length */
|
||||
EVP_CIPHER_CTX *outctx; /* Cipher context */
|
||||
|
||||
const EVP_MD *indigest; /* Digest type for MAC of packets received from him */
|
||||
int inmaclength; /* Length of MAC */
|
||||
|
||||
const EVP_MD *outdigest; /* Digest type for MAC of packets sent to him*/
|
||||
int outmaclength; /* Length of MAC */
|
||||
|
||||
int incompression; /* Compressionlevel, 0 = no compression */
|
||||
int outcompression; /* Compressionlevel, 0 = no compression */
|
||||
|
||||
struct node_t *nexthop; /* nearest node from us to him */
|
||||
struct edge_t *prevedge; /* nearest node from him to us */
|
||||
struct node_t *via; /* next hop for UDP packets */
|
||||
|
||||
avl_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */
|
||||
|
||||
avl_tree_t *edge_tree; /* Edges with this node as one of the endpoints */
|
||||
|
||||
struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */
|
||||
|
||||
uint32_t sent_seqno; /* Sequence number last sent to this node */
|
||||
uint32_t received_seqno; /* Sequence number last received from this node */
|
||||
uint32_t farfuture; /* Packets in a row that have arrived from the far future */
|
||||
unsigned char *late; /* Bitfield marking late packets */
|
||||
|
||||
length_t mtu; /* Maximum size of packets to send to this node */
|
||||
length_t minmtu; /* Probed minimum MTU */
|
||||
length_t maxmtu; /* Probed maximum MTU */
|
||||
int mtuprobes; /* Number of probes */
|
||||
event_t *mtuevent; /* Probe event */
|
||||
} node_t;
|
||||
|
||||
extern struct node_t *myself;
|
||||
extern avl_tree_t *node_tree;
|
||||
extern avl_tree_t *node_udp_tree;
|
||||
|
||||
extern void init_nodes(void);
|
||||
extern void exit_nodes(void);
|
||||
extern node_t *new_node(void) __attribute__((__malloc__));
|
||||
extern void free_node(node_t *n);
|
||||
extern void node_add(node_t *n);
|
||||
extern void node_del(node_t *n);
|
||||
extern node_t *lookup_node(char *name);
|
||||
extern node_t *lookup_node_udp(const sockaddr_t *sa);
|
||||
extern void update_node_udp(node_t *n, const sockaddr_t *sa);
|
||||
extern void dump_nodes(void);
|
||||
|
||||
#endif
|
||||
142
src/pidfile.c
Normal file
142
src/pidfile.c
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
pidfile.c - interact with pidfiles
|
||||
Copyright (c) 1995 Martin Schulze <Martin.Schulze@Linux.DE>
|
||||
|
||||
This file is part of the sysklogd package, a kernel and system log 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.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/* left unaltered for tinc -- Ivo Timmermans */
|
||||
/*
|
||||
* Sat Aug 19 13:24:33 MET DST 1995: Martin Schulze
|
||||
* First version (v0.2) released
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "pidfile.h"
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
/* read_pid
|
||||
*
|
||||
* Reads the specified pidfile and returns the read pid.
|
||||
* 0 is returned if either there's no pidfile, it's empty
|
||||
* or no pid can be read.
|
||||
*/
|
||||
pid_t read_pid(const char *pidfile) {
|
||||
FILE *f;
|
||||
long pid;
|
||||
|
||||
if(!(f = fopen(pidfile, "r"))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(fscanf(f, "%20ld", &pid) != 1) {
|
||||
pid = 0;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return (pid_t)pid;
|
||||
}
|
||||
|
||||
/* check_pid
|
||||
*
|
||||
* Reads the pid using read_pid and looks up the pid in the process
|
||||
* table (using /proc) to determine if the process already exists. If
|
||||
* so the pid is returned, otherwise 0.
|
||||
*/
|
||||
pid_t check_pid(const char *pidfile) {
|
||||
pid_t pid = read_pid(pidfile);
|
||||
|
||||
/* Amazing ! _I_ am already holding the pid file... */
|
||||
if((!pid) || (pid == getpid())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The 'standard' method of doing this is to try and do a 'fake' kill
|
||||
* of the process. If an ESRCH error is returned the process cannot
|
||||
* be found -- GW
|
||||
*/
|
||||
/* But... errno is usually changed only on error.. */
|
||||
errno = 0;
|
||||
|
||||
if(kill(pid, 0) && errno == ESRCH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* write_pid
|
||||
*
|
||||
* Writes the pid to the specified file. If that fails 0 is
|
||||
* returned, otherwise the pid.
|
||||
*/
|
||||
pid_t write_pid(const char *pidfile) {
|
||||
FILE *f;
|
||||
int fd;
|
||||
pid_t pid;
|
||||
|
||||
if((fd = open(pidfile, O_RDWR | O_CREAT, 0644)) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((f = fdopen(fd, "r+")) == NULL) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_FLOCK
|
||||
|
||||
if(flock(fd, LOCK_EX | LOCK_NB) == -1) {
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
pid = getpid();
|
||||
|
||||
if(!fprintf(f, "%ld\n", (long)pid)) {
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fflush(f);
|
||||
|
||||
#ifdef HAVE_FLOCK
|
||||
|
||||
if(flock(fd, LOCK_UN) == -1) {
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
fclose(f);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* remove_pid
|
||||
*
|
||||
* Remove the the specified file. The result from unlink(2)
|
||||
* is returned
|
||||
*/
|
||||
int remove_pid(const char *pidfile) {
|
||||
return unlink(pidfile);
|
||||
}
|
||||
#endif
|
||||
57
src/pidfile.h
Normal file
57
src/pidfile.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef TINC_PIDFILE_H
|
||||
#define TINC_PIDFILE_H
|
||||
|
||||
/*
|
||||
pidfile.h - interact with pidfiles
|
||||
Copyright (c) 1995 Martin Schulze <Martin.Schulze@Linux.DE>
|
||||
|
||||
This file is part of the sysklogd package, a kernel and system log 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.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
/* read_pid
|
||||
*
|
||||
* Reads the specified pidfile and returns the read pid.
|
||||
* 0 is returned if either there's no pidfile, it's empty
|
||||
* or no pid can be read.
|
||||
*/
|
||||
extern pid_t read_pid(const char *pidfile);
|
||||
|
||||
/* check_pid
|
||||
*
|
||||
* Reads the pid using read_pid and looks up the pid in the process
|
||||
* table (using /proc) to determine if the process already exists. If
|
||||
* so 1 is returned, otherwise 0.
|
||||
*/
|
||||
extern pid_t check_pid(const char *pidfile);
|
||||
|
||||
/* write_pid
|
||||
*
|
||||
* Writes the pid to the specified file. If that fails 0 is
|
||||
* returned, otherwise the pid.
|
||||
*/
|
||||
extern pid_t write_pid(const char *pidfile);
|
||||
|
||||
/* remove_pid
|
||||
*
|
||||
* Remove the the specified file. The result from unlink(2)
|
||||
* is returned
|
||||
*/
|
||||
extern int remove_pid(const char *pidfile);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
678
src/process.c
Normal file
678
src/process.c
Normal file
|
|
@ -0,0 +1,678 @@
|
|||
/*
|
||||
process.c -- process management functions
|
||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
#include "device.h"
|
||||
#include "edge.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "node.h"
|
||||
#include "pidfile.h"
|
||||
#include "process.h"
|
||||
#include "subnet.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* If zero, don't detach from the terminal. */
|
||||
bool do_detach = true;
|
||||
bool sighup = false;
|
||||
bool sigalrm = false;
|
||||
|
||||
extern char *identname;
|
||||
extern char *pidfilename;
|
||||
extern char **g_argv;
|
||||
extern bool use_logfile;
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
static sigset_t emptysigset;
|
||||
#endif
|
||||
|
||||
/* Some functions the less gifted operating systems might lack... */
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
extern char *identname;
|
||||
extern char *program_name;
|
||||
extern char **g_argv;
|
||||
|
||||
static SC_HANDLE manager = NULL;
|
||||
static SC_HANDLE service = NULL;
|
||||
static SERVICE_STATUS status = {0};
|
||||
static SERVICE_STATUS_HANDLE statushandle = 0;
|
||||
|
||||
bool install_service(void) {
|
||||
char command[4096] = "\"";
|
||||
char **argp;
|
||||
bool space;
|
||||
SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
|
||||
|
||||
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||
|
||||
if(!manager) {
|
||||
logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!strchr(program_name, '\\')) {
|
||||
GetCurrentDirectory(sizeof(command) - 1, command + 1);
|
||||
strncat(command, "\\", sizeof(command) - strlen(command));
|
||||
}
|
||||
|
||||
strncat(command, program_name, sizeof(command) - strlen(command));
|
||||
|
||||
strncat(command, "\"", sizeof(command) - strlen(command));
|
||||
|
||||
for(argp = g_argv + 1; *argp; argp++) {
|
||||
space = strchr(*argp, ' ');
|
||||
strncat(command, " ", sizeof(command) - strlen(command));
|
||||
|
||||
if(space) {
|
||||
strncat(command, "\"", sizeof(command) - strlen(command));
|
||||
}
|
||||
|
||||
strncat(command, *argp, sizeof(command) - strlen(command));
|
||||
|
||||
if(space) {
|
||||
strncat(command, "\"", sizeof(command) - strlen(command));
|
||||
}
|
||||
}
|
||||
|
||||
service = CreateService(manager, identname, identname,
|
||||
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
|
||||
command, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if(!service) {
|
||||
DWORD lasterror = GetLastError();
|
||||
logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror));
|
||||
|
||||
if(lasterror != ERROR_SERVICE_EXISTS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(service) {
|
||||
ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
|
||||
logger(LOG_INFO, "%s service installed", identname);
|
||||
} else {
|
||||
service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
|
||||
}
|
||||
|
||||
if(!StartService(service, 0, NULL)) {
|
||||
logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError()));
|
||||
} else {
|
||||
logger(LOG_INFO, "%s service started", identname);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remove_service(void) {
|
||||
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||
|
||||
if(!manager) {
|
||||
logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
|
||||
|
||||
if(!service) {
|
||||
logger(LOG_ERR, "Could not open %s service: %s", identname, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ControlService(service, SERVICE_CONTROL_STOP, &status)) {
|
||||
logger(LOG_ERR, "Could not stop %s service: %s", identname, winerror(GetLastError()));
|
||||
} else {
|
||||
logger(LOG_INFO, "%s service stopped", identname);
|
||||
}
|
||||
|
||||
if(!DeleteService(service)) {
|
||||
logger(LOG_ERR, "Could not remove %s service: %s", identname, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
logger(LOG_INFO, "%s service removed", identname);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
|
||||
switch(request) {
|
||||
case SERVICE_CONTROL_INTERROGATE:
|
||||
SetServiceStatus(statushandle, &status);
|
||||
return NO_ERROR;
|
||||
|
||||
case SERVICE_CONTROL_STOP:
|
||||
logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP");
|
||||
break;
|
||||
|
||||
case SERVICE_CONTROL_SHUTDOWN:
|
||||
logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN");
|
||||
break;
|
||||
|
||||
default:
|
||||
logger(LOG_WARNING, "Got unexpected request %d", (int)request);
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if(running) {
|
||||
running = false;
|
||||
status.dwWaitHint = 30000;
|
||||
status.dwCurrentState = SERVICE_STOP_PENDING;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
return NO_ERROR;
|
||||
} else {
|
||||
status.dwWaitHint = 0;
|
||||
status.dwCurrentState = SERVICE_STOPPED;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VOID WINAPI run_service(DWORD argc, LPTSTR *argv) {
|
||||
extern int main2(int argc, char **argv);
|
||||
|
||||
status.dwServiceType = SERVICE_WIN32;
|
||||
status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
|
||||
status.dwWin32ExitCode = 0;
|
||||
status.dwServiceSpecificExitCode = 0;
|
||||
status.dwCheckPoint = 0;
|
||||
|
||||
statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL);
|
||||
|
||||
if(!statushandle) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
|
||||
} else {
|
||||
status.dwWaitHint = 30000;
|
||||
status.dwCurrentState = SERVICE_START_PENDING;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
|
||||
status.dwWaitHint = 0;
|
||||
status.dwCurrentState = SERVICE_RUNNING;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
|
||||
main2(argc, argv);
|
||||
|
||||
status.dwWaitHint = 0;
|
||||
status.dwCurrentState = SERVICE_STOPPED;
|
||||
SetServiceStatus(statushandle, &status);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool init_service(void) {
|
||||
SERVICE_TABLE_ENTRY services[] = {
|
||||
{identname, run_service},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
if(!StartServiceCtrlDispatcher(services)) {
|
||||
if(GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
|
||||
return false;
|
||||
} else {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
/*
|
||||
check for an existing tinc for this net, and write pid to pidfile
|
||||
*/
|
||||
static bool write_pidfile(void) {
|
||||
pid_t pid;
|
||||
|
||||
pid = check_pid(pidfilename);
|
||||
|
||||
if(pid) {
|
||||
if(netname)
|
||||
fprintf(stderr, "A tincd is already running for net `%s' with pid %ld.\n",
|
||||
netname, (long)pid);
|
||||
else {
|
||||
fprintf(stderr, "A tincd is already running with pid %ld.\n", (long)pid);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* if it's locked, write-protected, or whatever */
|
||||
if(!write_pid(pidfilename)) {
|
||||
fprintf(stderr, "Couldn't write pid file %s: %s\n", pidfilename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
kill older tincd for this net
|
||||
*/
|
||||
bool kill_other(int signal) {
|
||||
#ifndef HAVE_MINGW
|
||||
pid_t pid;
|
||||
|
||||
pid = read_pid(pidfilename);
|
||||
|
||||
if(!pid) {
|
||||
if(netname)
|
||||
fprintf(stderr, "No other tincd is running for net `%s'.\n",
|
||||
netname);
|
||||
else {
|
||||
fprintf(stderr, "No other tincd is running.\n");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0; /* No error, sometimes errno is only changed on error */
|
||||
|
||||
/* ESRCH is returned when no process with that pid is found */
|
||||
if(kill(pid, signal) && errno == ESRCH) {
|
||||
if(netname)
|
||||
fprintf(stderr, "The tincd for net `%s' is no longer running. ",
|
||||
netname);
|
||||
else {
|
||||
fprintf(stderr, "The tincd is no longer running. ");
|
||||
}
|
||||
|
||||
fprintf(stderr, "Removing stale lock file.\n");
|
||||
remove_pid(pidfilename);
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return remove_service();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Detach from current terminal, write pidfile, kill parent
|
||||
*/
|
||||
bool detach(void) {
|
||||
setup_signals();
|
||||
|
||||
/* First check if we can open a fresh new pidfile */
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
|
||||
if(!write_pidfile()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If we succeeded in doing that, detach */
|
||||
|
||||
closelogger();
|
||||
#endif
|
||||
|
||||
if(do_detach) {
|
||||
#ifndef HAVE_MINGW
|
||||
|
||||
if(daemon(0, 0)) {
|
||||
fprintf(stderr, "Couldn't detach from terminal: %s",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Now UPDATE the pid in the pidfile, because we changed it... */
|
||||
|
||||
if(!write_pid(pidfilename)) {
|
||||
fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if(!statushandle) {
|
||||
exit(install_service());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
openlogger(identname, use_logfile ? LOGMODE_FILE : (do_detach ? LOGMODE_SYSLOG : LOGMODE_STDERR));
|
||||
|
||||
logger(LOG_NOTICE, "tincd %s starting, debug level %d",
|
||||
VERSION, debug_level);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PUTENV
|
||||
void unputenv(char *p) {
|
||||
char *e = strchr(p, '=');
|
||||
|
||||
if(!e) {
|
||||
return;
|
||||
}
|
||||
|
||||
int len = e - p;
|
||||
#ifndef HAVE_UNSETENV
|
||||
#ifdef HAVE_MINGW
|
||||
// Windows requires putenv("FOO=") to unset %FOO%
|
||||
len++;
|
||||
#endif
|
||||
#endif
|
||||
char var[len + 1];
|
||||
memcpy(var, p, len);
|
||||
var[len] = 0;
|
||||
#ifdef HAVE_UNSETENV
|
||||
unsetenv(var);
|
||||
#else
|
||||
// We must keep what we putenv() around in memory.
|
||||
// To do this without memory leaks, keep things in a list and reuse if possible.
|
||||
static list_t list = {};
|
||||
|
||||
for(list_node_t *node = list.head; node; node = node->next) {
|
||||
char *data = node->data;
|
||||
|
||||
if(!strcmp(data, var)) {
|
||||
putenv(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char *data = xstrdup(var);
|
||||
list_insert_tail(&list, data);
|
||||
putenv(data);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void putenv(const char *p) {}
|
||||
void unputenv(const char *p) {}
|
||||
#endif
|
||||
|
||||
bool execute_script(const char *name, char **envp) {
|
||||
#ifdef HAVE_SYSTEM
|
||||
char *scriptname;
|
||||
char *interpreter = NULL;
|
||||
config_t *cfg_interpreter;
|
||||
int status, len, i;
|
||||
|
||||
cfg_interpreter = lookup_config(config_tree, "ScriptsInterpreter");
|
||||
#ifndef HAVE_MINGW
|
||||
len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
|
||||
#else
|
||||
|
||||
if(cfg_interpreter) {
|
||||
len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
|
||||
} else {
|
||||
len = xasprintf(&scriptname, "\"%s/%s.bat\"", confbase, name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(len < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
scriptname[len - 1] = '\0';
|
||||
|
||||
/* First check if there is a script */
|
||||
if(access(scriptname + 1, F_OK)) {
|
||||
free(scriptname);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Custom scripts interpreter
|
||||
if(get_config_string(cfg_interpreter, &interpreter)) {
|
||||
// Force custom scripts interpreter allowing execution of scripts on android without execution flag (such as on /sdcard)
|
||||
free(scriptname);
|
||||
len = xasprintf(&scriptname, "%s \"%s/%s\"", interpreter, confbase, name);
|
||||
free(interpreter);
|
||||
|
||||
if(len < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ifdebug(STATUS) logger(LOG_INFO, "Executing script %s", name);
|
||||
|
||||
/* Set environment */
|
||||
|
||||
for(i = 0; envp[i]; i++) {
|
||||
putenv(envp[i]);
|
||||
}
|
||||
|
||||
scriptname[len - 1] = '\"';
|
||||
status = system(scriptname);
|
||||
|
||||
free(scriptname);
|
||||
|
||||
/* Unset environment */
|
||||
|
||||
for(i = 0; envp[i]; i++) {
|
||||
unputenv(envp[i]);
|
||||
}
|
||||
|
||||
if(status != -1) {
|
||||
#ifdef WEXITSTATUS
|
||||
|
||||
if(WIFEXITED(status)) { /* Child exited by itself */
|
||||
if(WEXITSTATUS(status)) {
|
||||
logger(LOG_ERR, "Script %s exited with non-zero status %d",
|
||||
name, WEXITSTATUS(status));
|
||||
return false;
|
||||
}
|
||||
} else if(WIFSIGNALED(status)) { /* Child was killed by a signal */
|
||||
logger(LOG_ERR, "Script %s was killed by signal %d (%s)",
|
||||
name, WTERMSIG(status), strsignal(WTERMSIG(status)));
|
||||
return false;
|
||||
} else { /* Something strange happened */
|
||||
logger(LOG_ERR, "Script %s terminated abnormally", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
} else {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Signal handlers.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
static void sigterm_handler(int a) {
|
||||
(void)a;
|
||||
logger(LOG_NOTICE, "Got %s signal", "TERM");
|
||||
|
||||
if(running) {
|
||||
running = false;
|
||||
} else {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void sigquit_handler(int a) {
|
||||
(void)a;
|
||||
logger(LOG_NOTICE, "Got %s signal", "QUIT");
|
||||
|
||||
if(running) {
|
||||
running = false;
|
||||
} else {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void fatal_signal_square(int a) {
|
||||
logger(LOG_ERR, "Got another fatal signal %d (%s): not restarting.", a,
|
||||
strsignal(a));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void fatal_signal_handler(int a) {
|
||||
struct sigaction act;
|
||||
logger(LOG_ERR, "Got fatal signal %d (%s)", a, strsignal(a));
|
||||
|
||||
if(do_detach) {
|
||||
logger(LOG_NOTICE, "Trying to re-execute in 5 seconds...");
|
||||
|
||||
act.sa_handler = fatal_signal_square;
|
||||
act.sa_mask = emptysigset;
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
|
||||
close_network_connections();
|
||||
sleep(5);
|
||||
remove_pid(pidfilename);
|
||||
execvp(g_argv[0], g_argv);
|
||||
} else {
|
||||
logger(LOG_NOTICE, "Not restarting.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void sighup_handler(int a) {
|
||||
(void)a;
|
||||
logger(LOG_NOTICE, "Got %s signal", "HUP");
|
||||
sighup = true;
|
||||
}
|
||||
|
||||
static void sigint_handler(int a) {
|
||||
(void)a;
|
||||
static int saved_debug_level = -1;
|
||||
|
||||
logger(LOG_NOTICE, "Got %s signal", "INT");
|
||||
|
||||
if(saved_debug_level != -1) {
|
||||
logger(LOG_NOTICE, "Reverting to old debug level (%d)",
|
||||
saved_debug_level);
|
||||
debug_level = saved_debug_level;
|
||||
saved_debug_level = -1;
|
||||
} else {
|
||||
logger(LOG_NOTICE,
|
||||
"Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d.",
|
||||
debug_level);
|
||||
saved_debug_level = debug_level;
|
||||
debug_level = 5;
|
||||
}
|
||||
}
|
||||
|
||||
static void sigalrm_handler(int a) {
|
||||
(void)a;
|
||||
logger(LOG_NOTICE, "Got %s signal", "ALRM");
|
||||
sigalrm = true;
|
||||
}
|
||||
|
||||
static void sigusr1_handler(int a) {
|
||||
(void)a;
|
||||
dump_connections();
|
||||
}
|
||||
|
||||
static void sigusr2_handler(int a) {
|
||||
(void)a;
|
||||
devops.dump_stats();
|
||||
dump_nodes();
|
||||
dump_edges();
|
||||
dump_subnets();
|
||||
}
|
||||
|
||||
static void sigwinch_handler(int a) {
|
||||
(void)a;
|
||||
do_purge = true;
|
||||
}
|
||||
|
||||
static void unexpected_signal_handler(int a) {
|
||||
(void)a;
|
||||
logger(LOG_WARNING, "Got unexpected signal %d (%s)", a, strsignal(a));
|
||||
}
|
||||
|
||||
static void ignore_signal_handler(int a) {
|
||||
(void)a;
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignored signal %d (%s)", a, strsignal(a));
|
||||
}
|
||||
|
||||
static struct {
|
||||
int signal;
|
||||
void (*handler)(int);
|
||||
} sighandlers[] = {
|
||||
{SIGHUP, sighup_handler},
|
||||
{SIGTERM, sigterm_handler},
|
||||
{SIGQUIT, sigquit_handler},
|
||||
{SIGSEGV, fatal_signal_handler},
|
||||
{SIGBUS, fatal_signal_handler},
|
||||
{SIGILL, fatal_signal_handler},
|
||||
{SIGPIPE, ignore_signal_handler},
|
||||
{SIGINT, sigint_handler},
|
||||
{SIGUSR1, sigusr1_handler},
|
||||
{SIGUSR2, sigusr2_handler},
|
||||
{SIGCHLD, ignore_signal_handler},
|
||||
{SIGALRM, sigalrm_handler},
|
||||
{SIGWINCH, sigwinch_handler},
|
||||
{SIGABRT, SIG_DFL},
|
||||
{0, NULL}
|
||||
};
|
||||
#endif
|
||||
|
||||
void setup_signals(void) {
|
||||
#ifndef HAVE_MINGW
|
||||
int i;
|
||||
struct sigaction act;
|
||||
|
||||
sigemptyset(&emptysigset);
|
||||
act.sa_handler = NULL;
|
||||
act.sa_mask = emptysigset;
|
||||
act.sa_flags = 0;
|
||||
|
||||
/* Set a default signal handler for every signal, errors will be
|
||||
ignored. */
|
||||
for(i = 1; i < NSIG; i++) {
|
||||
if(!do_detach) {
|
||||
act.sa_handler = SIG_DFL;
|
||||
} else {
|
||||
act.sa_handler = unexpected_signal_handler;
|
||||
}
|
||||
|
||||
sigaction(i, &act, NULL);
|
||||
}
|
||||
|
||||
/* If we didn't detach, allow coredumps */
|
||||
if(!do_detach) {
|
||||
sighandlers[3].handler = SIG_DFL;
|
||||
}
|
||||
|
||||
/* Then, for each known signal that we want to catch, assign a
|
||||
handler to the signal, with error checking this time. */
|
||||
for(i = 0; sighandlers[i].signal; i++) {
|
||||
act.sa_handler = sighandlers[i].handler;
|
||||
|
||||
if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
|
||||
fprintf(stderr, "Installing signal handler for signal %d (%s) failed: %s\n",
|
||||
sighandlers[i].signal, strsignal(sighandlers[i].signal),
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue