Initial SVN import of n2n v2

This commit is contained in:
Luca Deri 2016-10-23 10:46:15 +02:00
parent faaa47eda7
commit b1e9ce6d2a
67 changed files with 19669 additions and 0 deletions

131
CMakeLists.txt Normal file
View File

@ -0,0 +1,131 @@
project(n2n)
cmake_minimum_required(VERSION 2.6)
# N2n information
set(N2N_VERSION 2.1.0)
set(N2N_OSNAME ${CMAKE_SYSTEM})
# N2n specific params
if(NOT DEFINED N2N_OPTION_AES)
set(N2N_OPTION_AES ON)
endif(NOT DEFINED N2N_OPTION_AES)
add_definitions(-DN2N_VERSION='\"${N2N_VERSION}\"' -DN2N_OSNAME='\"${N2N_OSNAME}\"')
if(N2N_OPTION_AES)
add_definitions(-DN2N_HAVE_AES)
endif(N2N_OPTION_AES)
# Build information
if(NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS OFF)
endif(NOT DEFINED BUILD_SHARED_LIBS)
if(NOT DEFINED CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE None)
endif(NOT DEFINED CMAKE_BUILD_TYPE)
#set(CMAKE_BUILD_TYPE Debug)
#set(CMAKE_BUILD_TYPE Release)
#Ultrasparc64 users experiencing SIGBUS should try the following gcc options
#(thanks to Robert Gibbon)
#PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs
# None
set(CMAKE_C_FLAGS "-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs")
set(CMAKE_CXX_FLAGS "-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs")
# Debug
set(CMAKE_C_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
# Release
set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
## DEBUG FOR CMAKE
#message(${N2N_VERSION})
#message(${N2N_OSNAME})
##message(${CMAKE_BUILD_TYPE})
#message(${N2N_OPTION_AES})
## DEBUG FOR CMAKE
add_library(n2n n2n.c
n2n_keyfile.c
wire.c
minilzo.c
twofish.c
transform_null.c
transform_tf.c
transform_aes.c
tuntap_freebsd.c
tuntap_netbsd.c
tuntap_linux.c
tuntap_osx.c
version.c
)
if(DEFINED WIN32)
add_subdirectory(win32)
target_link_libraries(n2n n2n_win32)
endif(DEFINED WIN32)
if(N2N_OPTION_AES)
target_link_libraries(n2n crypto)
endif(N2N_OPTION_AES)
# For Solaris (or OpenSolaris?)
#target_link_libraries(n2n socket nsl)
add_executable(edge edge.c)
target_link_libraries(edge n2n)
add_executable(supernode sn.c)
target_link_libraries(supernode n2n)
add_executable(test test.c)
target_link_libraries(test n2n)
add_executable(benchmark benchmark.c)
target_link_libraries(benchmark n2n)
install(TARGETS edge supernode
RUNTIME DESTINATION sbin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
# Documentation
if(DEFINED UNIX)
add_dependencies(n2n doc)
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/doc)
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/edge.8.gz
COMMAND gzip -c ${PROJECT_SOURCE_DIR}/edge.8 > ${PROJECT_BINARY_DIR}/doc/edge.8.gz
DEPENDS ${PROJECT_SOURCE_DIR}/edge.8
)
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
COMMAND gzip -c ${PROJECT_SOURCE_DIR}/supernode.1 > ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
DEPENDS ${PROJECT_SOURCE_DIR}/supernode.1
)
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
COMMAND gzip -c ${PROJECT_SOURCE_DIR}/n2n_v2.7 > ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
DEPENDS ${PROJECT_SOURCE_DIR}/n2n_v2.7
)
add_custom_target(doc DEPENDS ${PROJECT_BINARY_DIR}/doc/edge.8.gz
${PROJECT_BINARY_DIR}/doc/supernode.1.gz
${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
)
set_source_files_properties(${PROJECT_BINARY_DIR}/doc/edge.8.gz
${PROJECT_BINARY_DIR}/doc/supernode.1.gz
${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
PROPERTIES GENERATED 1)
install(FILES ${PROJECT_BINARY_DIR}/doc/edge.8.gz
DESTINATION /usr/share/man8)
install(FILES ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
DESTINATION /usr/share/man1)
install(FILES ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
DESTINATION /usr/share/man7)
endif(DEFINED UNIX)

674
COPYING Normal file
View File

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. 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
them 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 prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. 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.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey 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;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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 that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
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.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
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.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 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/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
n2n Copyright (C) 2007-08 Luca Deri <deri@ntop.org>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

255
HACKING Normal file
View File

@ -0,0 +1,255 @@
file: HACKING
Last updated: 2010-01-01 09:55 UTC
--------
(C) 2008-2010 - Richard Andrews
This program and document 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 see <http://www.gnu.org/licenses/>
--------
This file describes the internals of n2n. Read this before starting to modify
the code. Because coding examples may be present in this document it is licensed
under the GPL rather than FDL.
SYMMETRIC NAT
-------------
Symmetric NAT is a form of firewall NAT in which an UDP packets are only passed
back to an inside host socket when the return packets originate from the outside
socket to which the initiating UDP packets were sent. This means that when an
inside host sends UDP to some outside socket; other hosts cannot piggyback on
this opening in the firewall to send data to the inside host.
When two inside hosts are both behind symmetric NAT, peer-to-peer packet
exchange is not possible via n2n. These hosts will require the supernode to
relay packets.
ARP CACHE
---------
n2n makes use of the host operating system's own ARP cache. Each edge node
allocates a random MAC address to itself. This MAC is constant for the life of
the edge process. ARP packets are passed around as broadcast ethernet packets
over n2n and these packets cause the native ARP cache to be updated.
Edge nodes send gratuitous ARP packets on startup. See GRATUITOUS ARP below.
REGISTRATION AND PEER-TO-PEER COMMUNICATION SETUP
-------------------------------------------------
A and B are edge nodes with public sockets Apub and Bpub; and private network
addresses A and B respectively. S is the supernode.
A sends {REGISTER,Amac} to S. S registers {Amac->Apub}.
B sends {REGISTER,Bmac} to S. S registers {Bmac->Bpub}.
Now ping from A to B.
A sends broadcast "arp who-has B" to S. S relays the packet to all known edge
nodes. B replies "B at Bmac" to supernode which forwards this to A. So now ping
A->B is known to be ping Amac(A)->Bmac(B). Note: gratuitous arp also requires
discussion.
In response to receiving the arp reply, Apub sends {REGISTER,Amac} to Bpub. If
Bpub receives the request it sends back {REGISTER_ACK,Amac} and also sends its
own {REGISTER,Bmac} request.
In response to receiving the "arp who-has", Bpub sends {REGISTER,Bmac} to Apub.
Now the OS has received the arp reply and sends ICMP to Bmac(B) via the tunnel
on A. A looks up Bmac in the peers list and encapsulates the packet to Bpub or
the supernode if the MAC is not found.
We assume that between two edge nodes, if Bpub receives a packet from Apub then
Apub can receive a packet from Bpub. This is the symmetric NAT case. Note: In
the symmetric NAT case, the public socket for a MAC address will be different
for direct contact when compared to information from the supernode.
When two edge nodes are both behind symmetric NAT they cannot establish direct
communication.
If A receives {REGISTER,Bmac} from B, A adds {Bmac->Bpub} to its peers list
knowing that Bmac is now reachable via that public socket. Similarly if B
receives {REGISTER,Amac} from A.
The supernode never forwards REGISTER messages because the public socket seen by
the supervisor for some edge (eg. A) may be different to the socket seen by
another edge due to the actions of symmetric NAT (alocating a new public socket
for the new outbound UDP "connection").
EDGE REGISTRATION DESIGN AMMENDMENTS (starting from 2008-04-10)
------------------------------------
* Send REGISTER on rx of PACKET or REGISTER only when dest_mac == device MAC
(do not send REGISTER on Rx of broadcast packets).
* After sending REGISTER add the new peer to pending_peers list; but
* Don't send REGISTER to a peer in pending_peers list
* Remove old entries from pending_peers at regular intervals
* On rx of REGISTER_ACK, move peer from pending_peers to known_peers for direct
comms and set last_seen=now
* On rx of any packet set last_seen=now in the known_peers entry (if it
exists); but do not add a new entry.
* If the public socket address for a known_peers entry changes, deleted it and
restart registration to the new peer.
* Peer sockets provided by the supernode are ignored unless no other entry
exists. Direct peer-to-peer sockets are always given more priority as the
supernode socket will not be usable for direct contact if the peer is behind
symmetric NAT.
The pending_peers list concept is to prevent massive registration traffic when
supernode relay is in force - this would occur if REGISTER was sent for every
incident packet sent via supernode. Periodic REGISTER attempts will still occur;
not for every received packet. In the case where the peer cannot be contacted
(eg. both peers behind symmetric NAT), then there will still be periodic
attempts. Suggest a pending timeout of about 60 sec.
A peer is only considered operational for peer-to-peer sending when a
REGISTER_ACK is returned. Once operational the peer is kept operational while
any direct packet communications are occurring. REGISTER is not required to
keep the path open through any firewalls; just some activity in one direction.
After an idle period; the peer should be deleted from the known_peers list. We
should not try to re-register when this time expires. If there is no data to
send then forget the peer. This helps scalability.
If a peer wants to be remembered it can send gratuitous ARP traffic which will
keep its entry in the known_peers list of any peers which already have the
entry.
peer = find_by_src_mac( hdr, known_peers ); /* return NULL or entry */
if ( peer )
{
peer_last_seen = time(NULL);
}
else
{
if ( ! is_broadcast( hdr ) ) /* ignore broadcasts */
{
if ( IS_REGISTER_ACK( hdr ) )
{
/* move from pending to known_peers */
set_peer_operational( hdr );
}
else
{
/* add to pending and send REGISTER - ignore if in pending. */
try_send_register( hdr )
}
}
}
(Notes):
* In testing it was noted that if a symmetric NAT firewall shuts down the UDP
association but the known_peers registration is still active, then the peer
becomes unreachable until the known_peers registration is deleted. Suggest two
ways to mitigate this problem:
(a) make the known_peers purge timeout a config paramter;
(b) send packets direct and via supernode if the registration is older than
eg. 60 sec.
GRATUITOUS ARP
--------------
In addition to the ARP who-has mechanism noted above, two edge nodes can become
aware of one another by gratuitous ARP. A gratuitous ARP packet is a broadcast
packet sent by a node for no other purpose than to announce its presence and
identify its MAC and IP address. Gratuitous ARP packets are to keep ARP caches
up to date so contacting the host will be faster after an long idle time.
MAN PAGES
---------
Look at a non-installed man page like this (linux/UNIX):
nroff -man edge.8 | less
PACKET message FORMAT
---------------------
All message encoding and decoding is contained in wire.c. The PACKET message is
of main concern as it is the most frequently transferred as it contains
encapsulated ethernet packets.
Version 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Version=2 ! TTL ! Flags !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 ! Community :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 ! ... Community ... !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 ! Source MAC Address :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24 : ! Destination MAC Address :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28 : !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 ! Socket Flags (v=IPv4) ! Destination UDP Port !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 ! Destination IPv4 Address !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 ! Transform ID !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 ! Payload
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
So each n2n PACKET has a 44 byte overhead. For a 1500 byte ethernet packet this
is roughly 3%.
Socket flags provides support for IPv6. In this case the PACKET message ends as
follows:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 ! Socket Flags (v=IPv6) ! Destination UDP Port !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 ! Destination IPv6 Address :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 : :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 : :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 : !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 ! Transform ID !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 ! Encapsulated ethernet payload
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-------
January 2010 - Richard Andrews <andrews@ntop.org>

50
INSTALL Normal file
View File

@ -0,0 +1,50 @@
INSTALL
To build the programs:
$ make
To install the programs and man pages:
$ make install
or
$ make PREFIX=/usr/local install
RPM Package
-----------
These steps should work with RPM based Linux distributions since rpmbuild was
split from the rpm utility (c RedHat 9).
To build an RPM the easy way follow these steps.
1. Build SRPM
$ cd n2n
$ scripts/mk_SRPM.sh
Look for where the src.rpm file was put ( "Wrote:" ).
2. Build binary RPM from SRPM
$ rpm -i path/to/n2n-<ver>.src.rpm
$ rpmbuild -bb n2n.spec
All this can be done as non-root user if you have a ~/.rpmmacros file with this
line in it:
%_topdir /home/username/rpmtopdir
To build an RPM the hard way follow these steps.
$ cp -a n2ndir n2n-2.0
$ tar czf n2n-2.0.tar.gz n2n-2.0
$ mv n2n-2.0.tar.gz /usr/src/redhat/SOURCES
$ cp n2ndir/n2n.spec /usr/src/redhat/SPECS
$ rpmbuild -bb n2n.spec

101
Makefile Normal file
View File

@ -0,0 +1,101 @@
N2N_VERSION=2.1.0
N2N_OSNAME=$(shell uname -p)
########
CC=gcc
DEBUG?=-g3
#OPTIMIZATION?=-O2
WARN?=-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs
#Ultrasparc64 users experiencing SIGBUS should try the following gcc options
#(thanks to Robert Gibbon)
PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs
N2N_DEFINES=
N2N_OBJS_OPT=
LIBS_EDGE_OPT=
N2N_OPTION_AES?="yes"
#N2N_OPTION_AES=no
ifeq ($(N2N_OPTION_AES), "yes")
N2N_DEFINES+="-DN2N_HAVE_AES"
LIBS_EDGE_OPT+=-lcrypto
endif
CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN) $(OPTIONS) $(PLATOPTS) $(N2N_DEFINES)
INSTALL=install
MKDIR=mkdir -p
INSTALL_PROG=$(INSTALL) -m755
INSTALL_DOC=$(INSTALL) -m644
# DESTDIR set in debian make system
PREFIX?=$(DESTDIR)/usr
#BINDIR=$(PREFIX)/bin
SBINDIR=$(PREFIX)/sbin
MANDIR?=$(PREFIX)/share/man
MAN1DIR=$(MANDIR)/man1
MAN7DIR=$(MANDIR)/man7
MAN8DIR=$(MANDIR)/man8
N2N_LIB=n2n.a
N2N_OBJS=n2n.o n2n_keyfile.o wire.o minilzo.o twofish.o \
transform_null.o transform_tf.o transform_aes.o \
tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o tuntap_osx.o version.o
LIBS_EDGE+=$(LIBS_EDGE_OPT)
LIBS_SN=
#For OpenSolaris (Solaris too?)
ifeq ($(shell uname), SunOS)
LIBS_EDGE+=-lsocket -lnsl
LIBS_SN+=-lsocket -lnsl
endif
APPS=edge
APPS+=supernode
DOCS=edge.8.gz supernode.1.gz n2n_v2.7.gz
all: $(APPS) $(DOCS)
edge: edge.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
$(CC) $(CFLAGS) edge.c $(N2N_LIB) $(LIBS_EDGE) -o edge
test: test.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
$(CC) $(CFLAGS) test.c $(N2N_LIB) $(LIBS_EDGE) -o test
supernode: sn.c $(N2N_LIB) n2n.h Makefile
$(CC) $(CFLAGS) sn.c $(N2N_LIB) $(LIBS_SN) -o supernode
benchmark: benchmark.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
$(CC) $(CFLAGS) benchmark.c $(N2N_LIB) $(LIBS_SN) -o benchmark
.c.o: n2n.h n2n_keyfile.h n2n_transforms.h n2n_wire.h twofish.h Makefile
$(CC) $(CFLAGS) -c $<
%.gz : %
gzip -c $< > $@
$(N2N_LIB): $(N2N_OBJS)
ar rcs $(N2N_LIB) $(N2N_OBJS)
# $(RANLIB) $@
version.o: Makefile
$(CC) $(CFLAGS) -DN2N_VERSION='"$(N2N_VERSION)"' -DN2N_OSNAME='"$(N2N_OSNAME)"' -c version.c
clean:
rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) test *.dSYM *~
install: edge supernode edge.8.gz supernode.1.gz n2n_v2.7.gz
echo "MANDIR=$(MANDIR)"
$(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR)
$(INSTALL_PROG) supernode $(SBINDIR)/
$(INSTALL_PROG) edge $(SBINDIR)/
$(INSTALL_DOC) edge.8.gz $(MAN8DIR)/
$(INSTALL_DOC) supernode.1.gz $(MAN1DIR)/
$(INSTALL_DOC) n2n_v2.7.gz $(MAN7DIR)/

6
NEW_FEATURES.txt Normal file
View File

@ -0,0 +1,6 @@
Between 2.0.x and 2.1.x
* Better ming Windows build support.
* Added -E flag to allow multicast ethernet traffic.

112
README.md Normal file
View File

@ -0,0 +1,112 @@
Edge node
---------
You need to start an edge node on each host you want to connect with the *same*
community.
0. become root
1. create tun device
# tunctl -t tun0
3. enable the edge process
# ./edge -d n2n0 -c mynetwork -k encryptme -u 99 -g 99 -m 3C:A0:12:34:56:78 -a 1.2.3.4 -l a.b.c.d:xyw
or
# N2N_KEY=encryptme ./edge -d n2n0 -c mynetwork -u 99 -g 99 -m 3C:A0:12:34:56:78 -a 1.2.3.4 -l a.b.c.d:xyw
Once you have this worked out, you can add the "-f" option to make edge detach
and run as a daemon.
Note that -u, -g and -f options are not available for Windows.
Supernode
--------
You need to start the supernode once
1. ./supernode -l 1234 -v
Dropping Root Privileges and SUID-Root Executables (UNIX)
--------------------------------------------------
The edge node uses superuser privileges to create a TAP network interface
device. Once this is created root privileges are not required and can constitute
a security hazard if there is some way for an attacker to take control of an
edge process while it is running. Edge will drop to a non-privileged user if you
specify the -u <uid> and -g <gid> options. These are numeric IDs. Consult
/etc/passwd.
You may choose to install edge SUID-root to do this:
1. Become root
2. chown root:root edge
3. chmod +s edge
done
Any user can now run edge. You may not want this, but it may be convenient and
safe if your host has only one login user.
Running As a Daemon (UNIX)
-------------------
Unless given "-f" as a command line option, edge will call daemon(3) after
successful setup. This causes the process to fork a child which closes stdin,
stdout and stderr then sets itself as process group leader. When this is done,
the edge command returns immediately and you will only see the edge process in
the process listings, eg. from ps or top.
If the edge command returns 0 then the daemon started successfully. If it
returns non-zero then edge failed to start up for some reason. When edge starts
running as a daemon, all logging goes to syslog daemon.info facility.
IPv6 Support
------------
n2n supports the carriage of IPv6 packets within the n2n tunnel. N2n does not
yet use IPv6 for transport between edges and supernodes.
To make IPv6 carriage work you need to manually add IPv6 addresses to the TAP
interfaces at each end. There is currently no way to specify an IPv6 address on
the edge command line.
eg. under linux:
on hostA:
[hostA] # /sbin/ip -6 addr add fc00:abcd:1234::7/48 dev n2n0
on hostB:
[hostB] # /sbin/ip -6 addr add fc00:abcd:1234::6/48 dev n2n0
You may find it useful to make use of tunctl from the uml-utilities
package. Tunctl allow you to bring up a TAP interface and configure addressing
prior to starting edge. It also allows edge to be restarted without the
interface closing (which would normally affect routing tables).
Once the IPv6 addresses are configured and edge started, IPv6 neighbor discovery
packets flow (get broadcast) and IPv6 entities self arrange. Test your IPv6
setup with ping6 - the IPv6 ping command.
Performance Notes
-----------------
The time taken to perform a ping test for various ciphers is given below:
Test: ping -f -l 8 -s 800 -c 10000 <far_edge>
AES (-O0) 11820
TF (-O0) 25761
TF (-O2) 20554
AES (-O3) 12532
TF (-O3) 14046
NULL (-O3) 10659
(C) 2007-2010 - Luca Deri <deri@ntop.org>, Richard Andrews <andrews@ntop.org>
(C) 2016 - ntop

110
benchmark.c Normal file
View File

@ -0,0 +1,110 @@
#include "n2n_wire.h"
#include "n2n_transforms.h"
#include "n2n.h"
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
uint8_t PKT_CONTENT[]={
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
/* Prototypes */
static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c );
int main( int argc, char * argv[] )
{
uint8_t pktbuf[N2N_PKT_BUF_SIZE];
n2n_trans_op_t transop_null;
n2n_common_t cmn;
n2n_PACKET_t pkt;
n2n_community_t c;
struct timeval t1;
struct timeval t2;
size_t i;
size_t n;
size_t idx;
size_t rem;
ssize_t nw;
ssize_t tdiff;
transop_null_init( &transop_null );
memset(c,0,sizeof(N2N_COMMUNITY_SIZE));
n=10000;
memcpy( c, "abc123def456", 12 );
gettimeofday( &t1, NULL );
for(i=0; i<n; ++i)
{
nw = do_encode_packet( pktbuf, N2N_PKT_BUF_SIZE, c);
nw += transop_null.fwd( &transop_null,
pktbuf+nw, N2N_PKT_BUF_SIZE-nw,
PKT_CONTENT, sizeof(PKT_CONTENT) );
idx=0;
rem=nw;
decode_common( &cmn, pktbuf, &rem, &idx);
decode_PACKET( &pkt, &cmn, pktbuf, &rem, &idx );
if ( 0 == (i%1000) )
{
fprintf(stderr,".");
}
}
gettimeofday( &t2, NULL );
tdiff = ((t2.tv_sec - t1.tv_sec) * 1000000) + (t2.tv_usec - t1.tv_usec);
fprintf( stderr, "\nrun %u times. (%u -> %u nsec each) %u.%06u -> %u.%06u.\n", i, tdiff, (tdiff *1000)/i, (uint32_t)t1.tv_sec, (uint32_t)t1.tv_usec, (uint32_t)t2.tv_sec, (uint32_t)t2.tv_usec );
return 0;
}
static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c )
{
n2n_mac_t destMac={0,1,2,3,4,5};
n2n_common_t cmn;
n2n_PACKET_t pkt;
size_t idx;
memset( &cmn, 0, sizeof(cmn) );
cmn.ttl = N2N_DEFAULT_TTL;
cmn.pc = n2n_packet;
cmn.flags=0; /* no options, not from supernode, no socket */
memcpy( cmn.community, c, N2N_COMMUNITY_SIZE );
memset( &pkt, 0, sizeof(pkt) );
memcpy( pkt.srcMac, destMac, N2N_MAC_SIZE);
memcpy( pkt.dstMac, destMac, N2N_MAC_SIZE);
pkt.sock.family=0; /* do not encode sock */
idx=0;
encode_PACKET( pktbuf, &idx, &cmn, &pkt );
traceEvent( TRACE_DEBUG, "encoded PACKET header of size=%u", (unsigned int)idx );
return idx;
}

7
debian/README.Debian vendored Normal file
View File

@ -0,0 +1,7 @@
n2n for Debian
--------------
This package depends on the kernel having the TUN/TAP driver configured in using
CONFIG_TUN=yes.
-- Richard Andrews <andrews@ntop.org> Thu, 10 Jul 2008 22:38:02 +1000

27
debian/changelog vendored Normal file
View File

@ -0,0 +1,27 @@
n2n (2.1.0-1) unstable; urgency=low
* Split package in two.
* Move manpage for edge to section 8.
* Install manpage for n2n_v2 to section 7.
* Create init.d files for the daemons.
-- Kim Hansen <kim@i9.dk> Sun, 04 Apr 2010 21:40:46 +0200
n2n (2.0-1) hardy; urgency=low
* New upstream release
-- Richard Andrews <andrews@ntop.org> Tue, 30 Oct 2009 22:26:04 +1100
n2n (1.3-1) hardy; urgency=low
* New upstream release
-- Richard Andrews <andrews@ntop.org> Fri, 30 Jan 2009 23:49:56 +1100
n2n (1.2-1) unstable; urgency=low
* Initial release
-- Richard Andrews <andrews@ntop.org> Thu, 10 Jul 2008 22:38:02 +1000

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
5

51
debian/control vendored Normal file
View File

@ -0,0 +1,51 @@
Source: n2n
Section: net
Priority: extra
Maintainer: Jean-Baptiste Denis <jeanbaptiste.denis@gmail.com>
Build-Depends: cdbs, debhelper (>= 5), libc6-dev (>= 2.0), dpatch, gcc, libssl-dev
Standards-Version: 3.7.2
Package: n2n
Architecture: any
Depends: n2n-edge, n2n-supernode
Description: dummy package for transition purposes
A dummy package for transition purposes that depends on n2n-edge and
n2n-supernode
Package: n2n-edge
Architecture: any
Suggests: uml-utilities
Depends: ${shlibs:Depends}, ${misc:Depends}
Conflicts: n2n (<< 2.1.0-1)
Replaces: n2n (<< 2.1.0-1)
Description: a layer-two peer-to-peer virtual private network (VPN)
n2n is a layer-two peer-to-peer virtual private network (VPN) which allows
users to exploit features typical of P2P applications at network instead of
application level. This means that users can gain native IP visibility (e.g.
two PCs belonging to the same n2n network can ping each other) and be
reachable with the same network IP address regardless of the network where
they currently belong. In a nutshell, as OpenVPN moved SSL from application
(e.g. used to implement the https protocol) to network protocol, n2n moves
P2P from application to network level.
.
Edge is the edge node daemon for n2n which creates a TAP interface to expose
the n2n virtual LAN.
Package: n2n-supernode
Architecture: any
Suggests: n2n-edge
Depends: ${shlibs:Depends}, ${misc:Depends}
Conflicts: n2n (<< 2.1.0-1)
Replaces: n2n (<< 2.1.0-1)
Description: a layer-two peer-to-peer virtual private network (VPN)
n2n is a layer-two peer-to-peer virtual private network (VPN) which allows
users to exploit features typical of P2P applications at network instead of
application level. This means that users can gain native IP visibility (e.g.
two PCs belonging to the same n2n network can ping each other) and be
reachable with the same network IP address regardless of the network where
they currently belong. In a nutshell, as OpenVPN moved SSL from application
(e.g. used to implement the https protocol) to network protocol, n2n moves
P2P from application to network level.
.
Supernode is a node introduction registry, broadcast conduit and packet relay
node for the n2n system.

23
debian/copyright vendored Normal file
View File

@ -0,0 +1,23 @@
This package was debianized by Jean-Baptiste Denis <jeanbaptiste.denis@gmail.com> on
Thu, 20 Nov 2008 23:53:02 +1000.
It was downloaded from http://www.ntop.org/n2n/
Upstream Author(s):
Luca Deri <deri@ntop.org>
Richard Andrews <andrews@ntop.org>
Copyright:
Copyright (C) 2008 Luca Deri
Copyright (C) 2008 Richard Andrews
License:
GPLv3
The Debian packaging is (C) 2008, Richard Andrews <andrews@ntop.org>,
Luca Deri <deri@ntop.org> and is licensed under the GPLv3, see
`/usr/share/common-licenses/GPL-3'.

21
debian/n2n-edge.default vendored Normal file
View File

@ -0,0 +1,21 @@
# Config file for the n2n edge node daemon.
# Sets the n2n community name. All edges within the same community appear on
# the same LAN (layer 2 network segment). Community name is 16 bytes in length.
N2N_COMMUNITY="MyCommunityName"
# Sets the twofish encryption key from ASCII text. All edges communicating must
# use the same key and community name.
N2N_KEY="MySecretCode"
# Sets the n2n supernode IP address to register to.
N2N_SUPERNODE="gw1.example.com"
# Sets the n2n virtual LAN IP address being claimed. This is a private IP
# address. All IP addresses in an n2n community typical belong to the same /24
# net work (ie. only the last octet of the IP addresses varies).
N2N_IP="10.10.10.11"
# Uncomment this to get edge node started.
#N2N_EDGE_CONFIG_DONE="yes"

1
debian/n2n-edge.docs vendored Normal file
View File

@ -0,0 +1 @@
README

129
debian/n2n-edge.init vendored Executable file
View File

@ -0,0 +1,129 @@
#! /bin/bash
### BEGIN INIT INFO
# Provides: n2n-edge
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: n2n-edge
# Description: Start n2n edge node daemon
### END INIT INFO
# Init script for n2n edge node
# Copyright (C) 2010 Kim Hansen <kim@i9.dk>
#
# 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/>.
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="n2n edge"
NAME=n2n-edge
DAEMON=/usr/sbin/edge
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Check config
if [ -z "$N2N_EDGE_CONFIG_DONE" ]
then
echo "Warning: n2n-edge not configured, edit config file in /etc/default/$NAME." 1>&2
exit 0
fi
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --user nobody --exec $DAEMON --test \
|| return 1
export N2N_KEY
start-stop-daemon --start --quiet --user nobody --exec $DAEMON -- \
-a $N2N_IP -c $N2N_COMMUNITY -l $N2N_SUPERNODE:7654 -u $(id -u nobody) -g $(id -g nobody) \
$DAEMON_ARGS \
|| return 2
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user nobody --exec $DAEMON
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
true # Set exit status to 0 (succes)

1
debian/n2n-edge.install vendored Normal file
View File

@ -0,0 +1 @@
edge /usr/sbin

2
debian/n2n-edge.manpages vendored Normal file
View File

@ -0,0 +1,2 @@
edge.8
n2n_v2.7

121
debian/n2n-supernode.init vendored Executable file
View File

@ -0,0 +1,121 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: n2n-supernode
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: n2n-supernode
# Description: Start n2n supernode
### END INIT INFO
# Init script for n2n supernode
# Copyright (C) 2010 Kim Hansen <kim@i9.dk>
#
# 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/>.
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="n2n supernode"
NAME=n2n-supernode
DAEMON=/usr/sbin/supernode
DAEMON_ARGS=""
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --user nobody --exec $DAEMON --test \
|| return 1
start-stop-daemon --start --quiet --user nobody --chuid nobody --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user nobody --exec $DAEMON
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
true # Set exit status to 0 (succes)

1
debian/n2n-supernode.install vendored Normal file
View File

@ -0,0 +1 @@
supernode /usr/sbin

1
debian/n2n-supernode.manpages vendored Normal file
View File

@ -0,0 +1 @@
supernode.1

5
debian/rules vendored Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/make -f
include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/class/makefile.mk

208
edge.8 Normal file
View File

@ -0,0 +1,208 @@
.TH edge 8 "17 Mar 2010" "n2n-2.1" "SUPERUSER COMMANDS"
.SH NAME
edge \- n2n edge node daemon
.SH SYNOPSIS
.B edge
[\-d <tun device>] \-a <tun IP address> \-c <community> {\-k <encrypt key>|\-K <keyfile>}
[\-s <netmask>] \-l <supernode host:port>
[\-p <local port>] [\-u <UID>] [\-g <GID>] [-f] [\-m <MAC address>] [\-r] [\-v]
.SH DESCRIPTION
N2N is a peer-to-peer VPN system. Edge is the edge node daemon for n2n which
creates a TAP interface to expose the n2n virtual LAN. On startup n2n creates
the TAP interface and configures it then registers with the supernode so it can
begin to find other nodes in the community.
.PP
.SH OPTIONS
.TP
\-d <name>
sets the TAP device name as seen in ifconfig. Only available on Linux.
.TP
\-a {<addr>|static:<addr>|dhcp:0.0.0.0}
sets the n2n virtual LAN IP address being claimed. This is a private IP
address. All IP addresses in an n2n community typical belong to the same /24
network (ie. only the last octet of the IP addresses varies). If DHCP is used to
assign interface addresses then specify the address as
.B -a dhcp:0.0.0.0
.TP
\-b
cause edge to perform hostname resolution for the supernode address each time
the supernode is periodically contacted. This can cause reliability problems
because all packet processing stops while the supernode address is resolved
which might take 15 seconds.
.TP
\-c <community>
sets the n2n community name. All edges within the same community appear on the
same LAN (layer 2 network segment). Community name is 16 bytes in length. A name
smaller than this is padded with 0x00 bytes and a name longer than this is
truncated to take the first 16 bytes.
.TP
\-h
write usage then exit.
.TP
\-k <keystring>
sets the twofish encryption key from ASCII text (see also N2N_KEY in
ENVIRONMENT). All edges communicating must use the same key and community
name. If neither -k nor -K is used to specify a key source then edge uses
cleartext mode (no encryption). The -k and -K options are mutually exclusive.
.TP
\-K <keyfile>
Reads a key-schedule file <keyfile> and populates the internal transform
operations with the data found there. This mechanism allows keys to roll at
pre-determined times for a group of hosts. Accurate time synchronisation is not
required as older keys can be decoded for some time after expiry. If neither -k
nor -K is used to specify a key source then edge uses cleartext mode (no
encryption). The -k and -K options are mutually exclusive.
.TP
\-l <addr>:<port>
sets the n2n supernode IP address and port to register to. Up to 2 supernodes
can be specified by two invocations of -l <addr>:<port>. eg.
.B edge -l 12.34.56.78:7654 -l 98.76.54.32:7654
.
.TP
\-p <num>
binds edge to the given UDP port. Useful for keeping the same external socket
across restarts of edge. This allows peer edges which know the edge socket to
continue p2p operation without going back to the supernode.
.TP
\-t <num>
binds the edge management system to the given UDP port. Default 5644. Use this
if you need to run multiple instance of edge; or something is bound to that
port.
.TP
\-u <uid>
causes the edge process to drop to the given user ID when privileges are no
longer required (UNIX).
.TP
\-g <gid>
causes the edge process to drop to the given group ID when privileges are no
longer required (UNIX).
.TP
\-f
disables daemon mode (UNIX) and causes edge to run in the foreground.
.TP
\-m <MAC>
start the TAP interface with the given MAC address. This is highly recommended
as it means the same address will be used if edge stops and restarts. If this is
not done, the ARP caches of all peers will be wrong and packets will not flow to
this edge until the next ARP refresh.
.TP
\-M <MTU>
set the MTU of the edge interface in bytes. MTU is the largest packet fragment
size allowed to be moved throught the interface. The default is 1400.
.TP
\-s <netmask>
set the netmask of edge interface in IPv4 dotted decimal notation. The default
is 255.255.255.0 (ie. /24).
.TP
\-r
enable IP packet forwarding/routing through the n2n virtual LAN. Without this
option, IP packets arriving over n2n are dropped if not for the -a <addr> (or
DHCP assigned) IP address of the edge interface.
.TP
\-E
accept packets destined for multicast ethernet MAC addresses. These addresses
are used in multicast ethernet and IPv6 neighbour discovery. If this option is
not present these multicast packets are discarded as most users do not need or
understand them.
.TP
\-v
more verbose logging (may be specified several times for more verbosity).
.SH ENVIRONMENT
.TP
.B N2N_KEY
set the encryption key so it is not visible on the command line
.SH EXAMPLES
.TP
.B edge \-d n2n0 \-c mynetwork \-k encryptme \-u 99 \-g 99 \-m DE:AD:BE:EF:01:23 \-a 192.168.254.7 \-p 50001 \-l 123.121.120.119:7654
Start edge with TAP device n2n0 on community "mynetwork" with community
supernode at 123.121.120.119 UDP port 7654 and bind the locally used UDP port to
50001. Use "encryptme" as the single permanent shared encryption key. Assign MAC
address DE:AD:BE:EF:01:23 to the n2n interface and drop to user=99 and group=99
after the TAP device is successfull configured.
.PP
Add the -f option to stop edge running as a daemon.
.PP
Somewhere else setup another edge with similar parameters, eg.
.B edge \-d n2n0 \-c mynetwork \-k encryptme \-u 99 \-g 99 \-m DE:AD:BE:EF:01:21 \-a 192.168.254.5 \-p 50001 \-l 123.121.120.119:7654
.PP
Now you can ping from 192.168.254.5 to 192.168.254.7.
.PP
The MAC address (-m <MAC>) and virtual IP address (-a <addr>) must be different
on all edges in the same community.
.SH KEY SCHEDULE FILES
(See
.B n2n_v2(7)
for more details).
The -K <keyfile> option reads a key schedule file.
.B edge \-d n2n0 \-c mynetwork \-K /path/to/file \-u 99 \-g 99 \-m DE:AD:BE:EF:01:21 \-a 192.168.254.5 \-p 50001 \-l 123.121.120.119:7654
.PP
The key schedule file consists of line, one per key in the schedule. The purpose
of key schedules is to encourage regular changing of the encryption keys used by
a community. The file structure also allows for full binary keys to be specified
as compared to the ASCII keys allowed by the single key injection. Each key line
consists of the following:
.B <from> <until> <transform> <data>
<from> and <until> are ASCII decimal values of the UNIX times during which the
key is valid. <transform> is the index of the transform that <data> applies
to. <data> is some text which is parsed by the transform module to derive the
key for that line.
Supported <transform> values are:
.TP
2 = TwoFish
<data> has the form <SA>_<hex_key>. eg.
.B 1252327945 1252328305 2 602_3d7c7769b34b2a4812f8c0e9d87ce9
This specifies security association number 602 and a 16-octet key of numeric
value 0x3d7c7769b34b2a4812f8c0e9d87ce9. <SA> is a 32-bit unsigned integer which
is used to identify the encryption key to the receiver. The SA number is sent
unencrypted so the receiver may find the correct key from the key
schedule. <hex_key> is up to 16 octets although shorter keys are allowed.
.TP
3 = AES-CBC
<data> has the form <SA>_<hex_key>. Same rules as TwoFish.
.SH CLEARTEXT MODE
If neither
.B -k
nor
.B -K
is specified then edge uses cleartext mode. In cleartext mode there is no
transform of the packet data it is simply encrypted. This is useful for
debugging n2n as packet contents can be seen clearly.
To prevent accidental exposure of data, edge only enters cleartext mode when no
keying parameters are specified. In the case where keying parameters are
specified but no valid keys can be determined, edge exits with an error at
startup. If all keys become invalid while running, edge continues to encode
using the last key that was valid.
.SH MANAGEMENT INTERFACE
Edge provides a very simple management system on UDP port 5644. Send a newline
to receive a status output. Send 'reload' to cause re-read of the
keyfile. Send 'stop' to cause edge to exit cleanly.
.SH EXIT STATUS
edge is a daemon and any exit is an error.
.SH AUTHORS
.TP
Richard Andrews
andrews (at) ntop.org - n2n-1 maintainer and main author of n2n-2
.TP
Luca Deri
deri (at) ntop.org - original author of n2n
.TP
Don Bindner
(--) - significant contributions to n2n-1
.SH SEE ALSO
ifconfig(8) supernode(1) tunctl(8) n2n_v2(7)

2412
edge.c Normal file

File diff suppressed because it is too large Load Diff

44
gen_keyfile.py Executable file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env python
# (c) 2009 Richard Andrews <andrews@ntop.org>
# Program to generate a n2n_edge key schedule file for twofish keys
# Each key line consists of the following element
# <from> <until> <txfrm> <opaque>
#
# where <from>, <until> are UNIX time_t values of key valid period
# <txfrm> is the transform ID (=2 for twofish)
# <opaque> is twofish-specific data as follows
# <sec_id>_<hex_key>
import os
import sys
import time
import random
NUM_KEYS=30
KEY_LIFE=300
KEY_LEN=16
now=time.time()
start_sa=random.randint( 0, 0xffffffff )
random.seed(now) # note now is a floating point time value
def rand_key():
key=str()
for i in range(0,KEY_LEN):
key += "%02x"%( random.randint( 0, 255) )
return key
for i in range(0,NUM_KEYS):
from_time = now + (KEY_LIFE * (i-1) )
until_time = now + (KEY_LIFE * (i+1) )
key = rand_key()
sa_idx = start_sa + i
transform_id = random.randint( 2, 3 )
sys.stdout.write("%d %d %d %d_%s\n"%(from_time, until_time, transform_id,sa_idx, key) )

417
lzoconf.h Normal file
View File

@ -0,0 +1,417 @@
/* lzoconf.h -- configuration for the LZO real-time data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
The LZO library 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.
The LZO library 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 the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __LZOCONF_H_INCLUDED
#define __LZOCONF_H_INCLUDED
#define LZO_VERSION 0x2030
#define LZO_VERSION_STRING "2.03"
#define LZO_VERSION_DATE "Apr 30 2008"
/* internal Autoconf configuration file - only used when building LZO */
#if defined(LZO_HAVE_CONFIG_H)
# include <config.h>
#endif
#include <limits.h>
#include <stddef.h>
/***********************************************************************
// LZO requires a conforming <limits.h>
************************************************************************/
#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
# error "invalid CHAR_BIT"
#endif
#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
# error "check your compiler installation"
#endif
#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
# error "your limits.h macros are broken"
#endif
/* get OS and architecture defines */
#ifndef __LZODEFS_H_INCLUDED
#include "lzodefs.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************
// some core defines
************************************************************************/
#if !defined(LZO_UINT32_C)
# if (UINT_MAX < LZO_0xffffffffL)
# define LZO_UINT32_C(c) c ## UL
# else
# define LZO_UINT32_C(c) ((c) + 0U)
# endif
#endif
/* memory checkers */
#if !defined(__LZO_CHECKER)
# if defined(__BOUNDS_CHECKING_ON)
# define __LZO_CHECKER 1
# elif defined(__CHECKER__)
# define __LZO_CHECKER 1
# elif defined(__INSURE__)
# define __LZO_CHECKER 1
# elif defined(__PURIFY__)
# define __LZO_CHECKER 1
# endif
#endif
/***********************************************************************
// integral and pointer types
************************************************************************/
/* lzo_uint should match size_t */
#if !defined(LZO_UINT_MAX)
# if defined(LZO_ABI_LLP64) /* WIN64 */
# if defined(LZO_OS_WIN64)
typedef unsigned __int64 lzo_uint;
typedef __int64 lzo_int;
# else
typedef unsigned long long lzo_uint;
typedef long long lzo_int;
# endif
# define LZO_UINT_MAX 0xffffffffffffffffull
# define LZO_INT_MAX 9223372036854775807LL
# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */
typedef unsigned int lzo_uint;
typedef int lzo_int;
# define LZO_UINT_MAX UINT_MAX
# define LZO_INT_MAX INT_MAX
# define LZO_INT_MIN INT_MIN
# elif (ULONG_MAX >= LZO_0xffffffffL)
typedef unsigned long lzo_uint;
typedef long lzo_int;
# define LZO_UINT_MAX ULONG_MAX
# define LZO_INT_MAX LONG_MAX
# define LZO_INT_MIN LONG_MIN
# else
# error "lzo_uint"
# endif
#endif
/* Integral types with 32 bits or more. */
#if !defined(LZO_UINT32_MAX)
# if (UINT_MAX >= LZO_0xffffffffL)
typedef unsigned int lzo_uint32;
typedef int lzo_int32;
# define LZO_UINT32_MAX UINT_MAX
# define LZO_INT32_MAX INT_MAX
# define LZO_INT32_MIN INT_MIN
# elif (ULONG_MAX >= LZO_0xffffffffL)
typedef unsigned long lzo_uint32;
typedef long lzo_int32;
# define LZO_UINT32_MAX ULONG_MAX
# define LZO_INT32_MAX LONG_MAX
# define LZO_INT32_MIN LONG_MIN
# else
# error "lzo_uint32"
# endif
#endif
/* The larger type of lzo_uint and lzo_uint32. */
#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
# define lzo_xint lzo_uint
#else
# define lzo_xint lzo_uint32
#endif
/* Memory model that allows to access memory at offsets of lzo_uint. */
#if !defined(__LZO_MMODEL)
# if (LZO_UINT_MAX <= UINT_MAX)
# define __LZO_MMODEL
# elif defined(LZO_HAVE_MM_HUGE_PTR)
# define __LZO_MMODEL_HUGE 1
# define __LZO_MMODEL __huge
# else
# define __LZO_MMODEL
# endif
#endif
/* no typedef here because of const-pointer issues */
#define lzo_bytep unsigned char __LZO_MMODEL *
#define lzo_charp char __LZO_MMODEL *
#define lzo_voidp void __LZO_MMODEL *
#define lzo_shortp short __LZO_MMODEL *
#define lzo_ushortp unsigned short __LZO_MMODEL *
#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
#define lzo_int32p lzo_int32 __LZO_MMODEL *
#define lzo_uintp lzo_uint __LZO_MMODEL *
#define lzo_intp lzo_int __LZO_MMODEL *
#define lzo_xintp lzo_xint __LZO_MMODEL *
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */
#define lzo_byte unsigned char __LZO_MMODEL
typedef int lzo_bool;
/***********************************************************************
// function types
************************************************************************/
/* name mangling */
#if !defined(__LZO_EXTERN_C)
# ifdef __cplusplus
# define __LZO_EXTERN_C extern "C"
# else
# define __LZO_EXTERN_C extern
# endif
#endif
/* calling convention */
#if !defined(__LZO_CDECL)
# define __LZO_CDECL __lzo_cdecl
#endif
/* DLL export information */
#if !defined(__LZO_EXPORT1)
# define __LZO_EXPORT1
#endif
#if !defined(__LZO_EXPORT2)
# define __LZO_EXPORT2
#endif
/* __cdecl calling convention for public C and assembly functions */
#if !defined(LZO_PUBLIC)
# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
#endif
#if !defined(LZO_EXTERN)
# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
#endif
#if !defined(LZO_PRIVATE)
# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL
#endif
/* function types */
typedef int
(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
typedef int
(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem,
const lzo_bytep dict, lzo_uint dict_len );
typedef int
(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem,
const lzo_bytep dict, lzo_uint dict_len );
/* Callback interface. Currently only the progress indicator ("nprogress")
* is used, but this may change in a future release. */
struct lzo_callback_t;
typedef struct lzo_callback_t lzo_callback_t;
#define lzo_callback_p lzo_callback_t __LZO_MMODEL *
/* malloc & free function types */
typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t)
(lzo_callback_p self, lzo_uint items, lzo_uint size);
typedef void (__LZO_CDECL *lzo_free_func_t)
(lzo_callback_p self, lzo_voidp ptr);
/* a progress indicator callback function */
typedef void (__LZO_CDECL *lzo_progress_func_t)
(lzo_callback_p, lzo_uint, lzo_uint, int);
struct lzo_callback_t
{
/* custom allocators (set to 0 to disable) */
lzo_alloc_func_t nalloc; /* [not used right now] */
lzo_free_func_t nfree; /* [not used right now] */
/* a progress indicator callback function (set to 0 to disable) */
lzo_progress_func_t nprogress;
/* NOTE: the first parameter "self" of the nalloc/nfree/nprogress
* callbacks points back to this struct, so you are free to store
* some extra info in the following variables. */
lzo_voidp user1;
lzo_xint user2;
lzo_xint user3;
};
/***********************************************************************
// error codes and prototypes
************************************************************************/
/* Error codes for the compression/decompression functions. Negative
* values are errors, positive values will be used for special but
* normal events.
*/
#define LZO_E_OK 0
#define LZO_E_ERROR (-1)
#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
#define LZO_E_INPUT_OVERRUN (-4)
#define LZO_E_OUTPUT_OVERRUN (-5)
#define LZO_E_LOOKBEHIND_OVERRUN (-6)
#define LZO_E_EOF_NOT_FOUND (-7)
#define LZO_E_INPUT_NOT_CONSUMED (-8)
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
#ifndef lzo_sizeof_dict_t
# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep))
#endif
/* lzo_init() should be the first function you call.
* Check the return code !
*
* lzo_init() is a macro to allow checking that the library and the
* compiler's view of various types are consistent.
*/
#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
(int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
(int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
(int)sizeof(lzo_callback_t))
LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
/* version functions (useful for shared libraries) */
LZO_EXTERN(unsigned) lzo_version(void);
LZO_EXTERN(const char *) lzo_version_string(void);
LZO_EXTERN(const char *) lzo_version_date(void);
LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
/* string functions */
LZO_EXTERN(int)
lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len);
LZO_EXTERN(lzo_voidp)
lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
LZO_EXTERN(lzo_voidp)
lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
LZO_EXTERN(lzo_voidp)
lzo_memset(lzo_voidp _s, int _c, lzo_uint _len);
/* checksum functions */
LZO_EXTERN(lzo_uint32)
lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len);
LZO_EXTERN(lzo_uint32)
lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len);
LZO_EXTERN(const lzo_uint32p)
lzo_get_crc32_table(void);
/* misc. */
LZO_EXTERN(int) _lzo_config_check(void);
typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t;
/* align a char pointer on a boundary that is a multiple of `size' */
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
#define LZO_PTR_ALIGN_UP(_ptr,_size) \
((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
/***********************************************************************
// deprecated macros - only for backward compatibility with LZO v1.xx
************************************************************************/
#if defined(LZO_CFG_COMPAT)
#define __LZOCONF_H 1
#if defined(LZO_ARCH_I086)
# define __LZO_i386 1
#elif defined(LZO_ARCH_I386)
# define __LZO_i386 1
#endif
#if defined(LZO_OS_DOS16)
# define __LZO_DOS 1
# define __LZO_DOS16 1
#elif defined(LZO_OS_DOS32)
# define __LZO_DOS 1
#elif defined(LZO_OS_WIN16)
# define __LZO_WIN 1
# define __LZO_WIN16 1
#elif defined(LZO_OS_WIN32)
# define __LZO_WIN 1
#endif
#define __LZO_CMODEL
#define __LZO_DMODEL
#define __LZO_ENTRY __LZO_CDECL
#define LZO_EXTERN_CDECL LZO_EXTERN
#define LZO_ALIGN LZO_PTR_ALIGN_UP
#define lzo_compress_asm_t lzo_compress_t
#define lzo_decompress_asm_t lzo_decompress_t
#endif /* LZO_CFG_COMPAT */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* already included */
/* vim:set ts=4 et: */

1807
lzodefs.h Normal file

File diff suppressed because it is too large Load Diff

4112
minilzo.c Normal file

File diff suppressed because it is too large Load Diff

106
minilzo.h Normal file
View File

@ -0,0 +1,106 @@
/* minilzo.h -- mini subset of the LZO real-time data compression library
This file is part of the LZO real-time data compression library.
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
The LZO library 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.
The LZO library 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 the LZO library; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
*/
/*
* NOTE:
* the full LZO package can be found at
* http://www.oberhumer.com/opensource/lzo/
*/
#ifndef __MINILZO_H
#define __MINILZO_H
#define MINILZO_VERSION 0x2030
#ifdef __LZOCONF_H
# error "you cannot use both LZO and miniLZO"
#endif
#undef LZO_HAVE_CONFIG_H
#include "lzoconf.h"
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
# error "version mismatch in header files"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***********************************************************************
//
************************************************************************/
/* Memory required for the wrkmem parameter.
* When the required size is 0, you can also pass a NULL pointer.
*/
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
#define LZO1X_MEM_DECOMPRESS (0)
/* compression */
LZO_EXTERN(int)
lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem );
/* decompression */
LZO_EXTERN(int)
lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
/* safe decompression with overrun testing */
LZO_EXTERN(int)
lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
lzo_bytep dst, lzo_uintp dst_len,
lzo_voidp wrkmem /* NOT USED */ );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* already included */

455
n2n.c Normal file
View File

@ -0,0 +1,455 @@
/*
* (C) 2007-09 - Luca Deri <deri@ntop.org>
* Richard Andrews <andrews@ntop.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 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/>
*
* Code contributions courtesy of:
* Massimo Torquati <torquati@ntop.org>
* Matt Gilg
*
*/
#include "n2n.h"
#include "minilzo.h"
#include <assert.h>
#if defined(DEBUG)
# define PURGE_REGISTRATION_FREQUENCY 60
# define REGISTRATION_TIMEOUT 120
#else /* #if defined(DEBUG) */
# define PURGE_REGISTRATION_FREQUENCY 60
# define REGISTRATION_TIMEOUT (60*20)
#endif /* #if defined(DEBUG) */
const uint8_t broadcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
const uint8_t multicast_addr[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */
const uint8_t ipv6_multicast_addr[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; /* First 2 bytes are meaningful */
/* ************************************** */
SOCKET open_socket(int local_port, int bind_any) {
SOCKET sock_fd;
struct sockaddr_in local_address;
int sockopt = 1;
if((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
traceEvent(TRACE_ERROR, "Unable to create socket [%s][%d]\n",
strerror(errno), sock_fd);
return(-1);
}
#ifndef WIN32
/* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */
#endif
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt));
memset(&local_address, 0, sizeof(local_address));
local_address.sin_family = AF_INET;
local_address.sin_port = htons(local_port);
local_address.sin_addr.s_addr = htonl(bind_any?INADDR_ANY:INADDR_LOOPBACK);
if(bind(sock_fd, (struct sockaddr*) &local_address, sizeof(local_address)) == -1) {
traceEvent(TRACE_ERROR, "Bind error [%s]\n", strerror(errno));
return(-1);
}
return(sock_fd);
}
int traceLevel = 2 /* NORMAL */;
int useSyslog = 0, syslog_opened = 0;
#define N2N_TRACE_DATESIZE 32
void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...) {
va_list va_ap;
if(eventTraceLevel <= traceLevel) {
char buf[2048];
char out_buf[640];
char theDate[N2N_TRACE_DATESIZE];
char *extra_msg = "";
time_t theTime = time(NULL);
#ifdef WIN32
int i;
#endif
/* We have two paths - one if we're logging, one if we aren't
* Note that the no-log case is those systems which don't support it (WIN32),
* those without the headers !defined(USE_SYSLOG)
* those where it's parametrically off...
*/
memset(buf, 0, sizeof(buf));
strftime(theDate, N2N_TRACE_DATESIZE, "%d/%b/%Y %H:%M:%S", localtime(&theTime));
va_start (va_ap, format);
vsnprintf(buf, sizeof(buf)-1, format, va_ap);
va_end(va_ap);
if(eventTraceLevel == 0 /* TRACE_ERROR */)
extra_msg = "ERROR: ";
else if(eventTraceLevel == 1 /* TRACE_WARNING */)
extra_msg = "WARNING: ";
while(buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
#ifndef WIN32
if(useSyslog) {
if(!syslog_opened) {
openlog("n2n", LOG_PID, LOG_DAEMON);
syslog_opened = 1;
}
snprintf(out_buf, sizeof(out_buf), "%s%s", extra_msg, buf);
syslog(LOG_INFO, "%s", out_buf);
} else {
snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, file, line, extra_msg, buf);
printf("%s\n", out_buf);
fflush(stdout);
}
#else
/* this is the WIN32 code */
for(i=strlen(file)-1; i>0; i--) if(file[i] == '\\') { i++; break; };
snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, &file[i], line, extra_msg, buf);
printf("%s\n", out_buf);
fflush(stdout);
#endif
}
}
/* *********************************************** */
/* addr should be in network order. Things are so much simpler that way. */
char* intoa(uint32_t /* host order */ addr, char* buf, uint16_t buf_len) {
char *cp, *retStr;
uint8_t byteval;
int n;
cp = &buf[buf_len];
*--cp = '\0';
n = 4;
do {
byteval = addr & 0xff;
*--cp = byteval % 10 + '0';
byteval /= 10;
if (byteval > 0) {
*--cp = byteval % 10 + '0';
byteval /= 10;
if (byteval > 0)
*--cp = byteval + '0';
}
*--cp = '.';
addr >>= 8;
} while (--n > 0);
/* Convert the string to lowercase */
retStr = (char*)(cp+1);
return(retStr);
}
/* *********************************************** */
char * macaddr_str( macstr_t buf,
const n2n_mac_t mac )
{
snprintf(buf, N2N_MACSTR_SIZE, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF,
mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF);
return(buf);
}
/* *********************************************** */
uint8_t is_multi_broadcast(const uint8_t * dest_mac) {
int is_broadcast = ( memcmp(broadcast_addr, dest_mac, 6) == 0 );
int is_multicast = ( memcmp(multicast_addr, dest_mac, 3) == 0 );
int is_ipv6_multicast = ( memcmp(ipv6_multicast_addr, dest_mac, 2) == 0 );
return is_broadcast || is_multicast || is_ipv6_multicast;
}
/* http://www.faqs.org/rfcs/rfc908.html */
/* *********************************************** */
char* msg_type2str(uint16_t msg_type) {
switch(msg_type) {
case MSG_TYPE_REGISTER: return("MSG_TYPE_REGISTER");
case MSG_TYPE_DEREGISTER: return("MSG_TYPE_DEREGISTER");
case MSG_TYPE_PACKET: return("MSG_TYPE_PACKET");
case MSG_TYPE_REGISTER_ACK: return("MSG_TYPE_REGISTER_ACK");
case MSG_TYPE_REGISTER_SUPER: return("MSG_TYPE_REGISTER_SUPER");
case MSG_TYPE_REGISTER_SUPER_ACK: return("MSG_TYPE_REGISTER_SUPER_ACK");
case MSG_TYPE_REGISTER_SUPER_NAK: return("MSG_TYPE_REGISTER_SUPER_NAK");
case MSG_TYPE_FEDERATION: return("MSG_TYPE_FEDERATION");
default: return("???");
}
return("???");
}
/* *********************************************** */
void hexdump(const uint8_t * buf, size_t len)
{
size_t i;
if ( 0 == len ) { return; }
for(i=0; i<len; i++)
{
if((i > 0) && ((i % 16) == 0)) { printf("\n"); }
printf("%02X ", buf[i] & 0xFF);
}
printf("\n");
}
/* *********************************************** */
void print_n2n_version() {
printf("Welcome to n2n v.%s for %s\n"
"Built on %s\n"
"Copyright 2007-09 - http://www.ntop.org\n\n",
n2n_sw_version, n2n_sw_osName, n2n_sw_buildDate);
}
/** Find the peer entry in list with mac_addr equal to mac.
*
* Does not modify the list.
*
* @return NULL if not found; otherwise pointer to peer entry.
*/
struct peer_info * find_peer_by_mac( struct peer_info * list, const n2n_mac_t mac )
{
while(list != NULL)
{
if( 0 == memcmp(mac, list->mac_addr, 6) )
{
return list;
}
list = list->next;
}
return NULL;
}
/** Return the number of elements in the list.
*
*/
size_t peer_list_size( const struct peer_info * list )
{
size_t retval=0;
while ( list )
{
++retval;
list = list->next;
}
return retval;
}
/** Add new to the head of list. If list is NULL; create it.
*
* The item new is added to the head of the list. New is modified during
* insertion. list takes ownership of new.
*/
void peer_list_add( struct peer_info * * list,
struct peer_info * new )
{
new->next = *list;
new->last_seen = time(NULL);
*list = new;
}
size_t purge_expired_registrations( struct peer_info ** peer_list ) {
static time_t last_purge = 0;
time_t now = time(NULL);
size_t num_reg = 0;
if((now - last_purge) < PURGE_REGISTRATION_FREQUENCY) return 0;
traceEvent(TRACE_INFO, "Purging old registrations");
num_reg = purge_peer_list( peer_list, now-REGISTRATION_TIMEOUT );
last_purge = now;
traceEvent(TRACE_INFO, "Remove %ld registrations", num_reg);
return num_reg;
}
/** Purge old items from the peer_list and return the number of items that were removed. */
size_t purge_peer_list( struct peer_info ** peer_list,
time_t purge_before )
{
struct peer_info *scan;
struct peer_info *prev;
size_t retval=0;
scan = *peer_list;
prev = NULL;
while(scan != NULL)
{
if(scan->last_seen < purge_before)
{
struct peer_info *next = scan->next;
if(prev == NULL)
{
*peer_list = next;
}
else
{
prev->next = next;
}
++retval;
free(scan);
scan = next;
}
else
{
prev = scan;
scan = scan->next;
}
}
return retval;
}
/** Purge all items from the peer_list and return the number of items that were removed. */
size_t clear_peer_list( struct peer_info ** peer_list )
{
struct peer_info *scan;
struct peer_info *prev;
size_t retval=0;
scan = *peer_list;
prev = NULL;
while(scan != NULL)
{
struct peer_info *next = scan->next;
if(prev == NULL)
{
*peer_list = next;
}
else
{
prev->next = next;
}
++retval;
free(scan);
scan = next;
}
return retval;
}
static uint8_t hex2byte( const char * s )
{
char tmp[3];
tmp[0]=s[0];
tmp[1]=s[1];
tmp[2]=0; /* NULL term */
return((uint8_t)strtol( s, NULL, 16 ));
}
extern int str2mac( uint8_t * outmac /* 6 bytes */, const char * s )
{
size_t i;
/* break it down as one case for the first "HH", the 5 x through loop for
* each ":HH" where HH is a two hex nibbles in ASCII. */
*outmac=hex2byte(s);
++outmac;
s+=2; /* don't skip colon yet - helps generalise loop. */
for (i=1; i<6; ++i )
{
s+=1;
*outmac=hex2byte(s);
++outmac;
s+=2;
}
return 0; /* ok */
}
extern char * sock_to_cstr( n2n_sock_str_t out,
const n2n_sock_t * sock )
{
int r;
if ( NULL == out ) { return NULL; }
memset(out, 0, N2N_SOCKBUF_SIZE);
if ( AF_INET6 == sock->family )
{
/* INET6 not written yet */
r = snprintf( out, N2N_SOCKBUF_SIZE, "XXXX:%hu", sock->port );
return out;
}
else
{
const uint8_t * a = sock->addr.v4;
r = snprintf( out, N2N_SOCKBUF_SIZE, "%hu.%hu.%hu.%hu:%hu",
(a[0] & 0xff), (a[1] & 0xff), (a[2] & 0xff), (a[3] & 0xff), sock->port );
return out;
}
}
/* @return zero if the two sockets are equivalent. */
int sock_equal( const n2n_sock_t * a,
const n2n_sock_t * b )
{
if ( a->port != b->port ) { return 1; }
if ( a->family != b->family ) { return 1; }
switch (a->family) /* they are the same */
{
case AF_INET:
if ( 0 != memcmp( a->addr.v4, b->addr.v4, IPV4_SIZE ) ) { return 1;};
break;
default:
if ( 0 != memcmp( a->addr.v6, b->addr.v6, IPV6_SIZE ) ) { return 1;};
break;
}
return 0;
}

254
n2n.h Normal file
View File

@ -0,0 +1,254 @@
/*
* (C) 2007-09 - Luca Deri <deri@ntop.org>
* Richard Andrews <andrews@ntop.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 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/>
*
* Code contributions courtesy of:
* Babak Farrokhi <babak@farrokhi.net> [FreeBSD port]
* Lukasz Taczuk
*
*/
#ifndef _N2N_H_
#define _N2N_H_
/*
tunctl -t tun0
tunctl -t tun1
ifconfig tun0 1.2.3.4 up
ifconfig tun1 1.2.3.5 up
./edge -d tun0 -l 2000 -r 127.0.0.1:3000 -c hello
./edge -d tun1 -l 3000 -r 127.0.0.1:2000 -c hello
tunctl -u UID -t tunX
*/
#if defined(__APPLE__) && defined(__MACH__)
#define _DARWIN_
#endif
/* Some capability defaults which can be reset for particular platforms. */
#define N2N_HAVE_DAEMON 1
#define N2N_HAVE_SETUID 1
/* #define N2N_CAN_NAME_IFACE */
/* Moved here to define _CRT_SECURE_NO_WARNINGS before all the including takes place */
#ifdef WIN32
#include "win32/n2n_win32.h"
#undef N2N_HAVE_DAEMON
#undef N2N_HAVE_SETUID
#endif
#include <time.h>
#include <ctype.h>
#include <stdlib.h>
#ifndef WIN32
#include <netdb.h>
#endif
#ifndef _MSC_VER
#include <getopt.h>
#endif /* #ifndef _MSC_VER */
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#ifndef WIN32
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <pthread.h>
#ifdef __linux__
#include <linux/if.h>
#include <linux/if_tun.h>
#define N2N_CAN_NAME_IFACE 1
#endif /* #ifdef __linux__ */
#ifdef __FreeBSD__
#include <netinet/in_systm.h>
#endif /* #ifdef __FreeBSD__ */
#include <syslog.h>
#include <sys/wait.h>
#define ETH_ADDR_LEN 6
struct ether_hdr
{
uint8_t dhost[ETH_ADDR_LEN];
uint8_t shost[ETH_ADDR_LEN];
uint16_t type; /* higher layer protocol encapsulated */
} __attribute__ ((__packed__));
typedef struct ether_hdr ether_hdr_t;
#ifdef __sun__
#include <sys/sysmacros.h> /* MIN() and MAX() declared here */
#undef N2N_HAVE_DAEMON
#endif /* #ifdef __sun__ */
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#define closesocket(a) close(a)
#endif /* #ifndef WIN32 */
#include <string.h>
#include <stdarg.h>
#ifdef WIN32
#include "win32/wintap.h"
#endif /* #ifdef WIN32 */
#include "n2n_wire.h"
/* N2N_IFNAMSIZ is needed on win32 even if dev_name is not used after declaration */
#define N2N_IFNAMSIZ 16 /* 15 chars * NULL */
#ifndef WIN32
typedef struct tuntap_dev {
int fd;
uint8_t mac_addr[6];
uint32_t ip_addr, device_mask;
uint16_t mtu;
char dev_name[N2N_IFNAMSIZ];
} tuntap_dev;
#define SOCKET int
#endif /* #ifndef WIN32 */
#define QUICKLZ 1
/* N2N packet header indicators. */
#define MSG_TYPE_REGISTER 1
#define MSG_TYPE_DEREGISTER 2
#define MSG_TYPE_PACKET 3
#define MSG_TYPE_REGISTER_ACK 4
#define MSG_TYPE_REGISTER_SUPER 5
#define MSG_TYPE_REGISTER_SUPER_ACK 6
#define MSG_TYPE_REGISTER_SUPER_NAK 7
#define MSG_TYPE_FEDERATION 8
/* Set N2N_COMPRESSION_ENABLED to 0 to disable lzo1x compression of ethernet
* frames. Doing this will break compatibility with the standard n2n packet
* format so do it only for experimentation. All edges must be built with the
* same value if they are to understand each other. */
#define N2N_COMPRESSION_ENABLED 1
#define DEFAULT_MTU 1400
/** Common type used to hold stringified IP addresses. */
typedef char ipstr_t[32];
/** Common type used to hold stringified MAC addresses. */
#define N2N_MACSTR_SIZE 32
typedef char macstr_t[N2N_MACSTR_SIZE];
struct peer_info {
struct peer_info * next;
n2n_community_t community_name;
n2n_mac_t mac_addr;
n2n_sock_t sock;
time_t last_seen;
};
struct n2n_edge; /* defined in edge.c */
typedef struct n2n_edge n2n_edge_t;
/* ************************************** */
#define TRACE_ERROR 0, __FILE__, __LINE__
#define TRACE_WARNING 1, __FILE__, __LINE__
#define TRACE_NORMAL 2, __FILE__, __LINE__
#define TRACE_INFO 3, __FILE__, __LINE__
#define TRACE_DEBUG 4, __FILE__, __LINE__
/* ************************************** */
#define SUPERNODE_IP "127.0.0.1"
#define SUPERNODE_PORT 1234
/* ************************************** */
#ifndef max
#define max(a, b) ((a < b) ? b : a)
#endif
#ifndef min
#define min(a, b) ((a > b) ? b : a)
#endif
/* ************************************** */
/* Variables */
/* extern TWOFISH *tf; */
extern int traceLevel;
extern int useSyslog;
extern const uint8_t broadcast_addr[6];
extern const uint8_t multicast_addr[6];
/* Functions */
extern void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...);
extern int tuntap_open(tuntap_dev *device, char *dev, const char *address_mode, char *device_ip,
char *device_mask, const char * device_mac, int mtu);
extern int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len);
extern int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len);
extern void tuntap_close(struct tuntap_dev *tuntap);
extern void tuntap_get_address(struct tuntap_dev *tuntap);
extern SOCKET open_socket(int local_port, int bind_any);
extern char* intoa(uint32_t addr, char* buf, uint16_t buf_len);
extern char* macaddr_str(macstr_t buf, const n2n_mac_t mac);
extern int str2mac( uint8_t * outmac /* 6 bytes */, const char * s );
extern char * sock_to_cstr( n2n_sock_str_t out,
const n2n_sock_t * sock );
extern int sock_equal( const n2n_sock_t * a,
const n2n_sock_t * b );
extern uint8_t is_multi_broadcast(const uint8_t * dest_mac);
extern char* msg_type2str(uint16_t msg_type);
extern void hexdump(const uint8_t * buf, size_t len);
void print_n2n_version();
/* Operations on peer_info lists. */
struct peer_info * find_peer_by_mac( struct peer_info * list,
const n2n_mac_t mac );
void peer_list_add( struct peer_info * * list,
struct peer_info * new );
size_t peer_list_size( const struct peer_info * list );
size_t purge_peer_list( struct peer_info ** peer_list,
time_t purge_before );
size_t clear_peer_list( struct peer_info ** peer_list );
size_t purge_expired_registrations( struct peer_info ** peer_list );
/* version.c */
extern char *n2n_sw_version, *n2n_sw_osName, *n2n_sw_buildDate;
#endif /* _N2N_H_ */

52
n2n.spec Normal file
View File

@ -0,0 +1,52 @@
Summary: N2N peer-to-peer virtual private network system.
Name: n2n
Version: 2.1.0
Release: 1
License: GPLv3
Vendor: ntop.org
Group: None
URL: http://www.ntop.org/n2n
Source0: %{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
%description
N2N is a peer-to-peer virtual private network system. N2N uses the universal
TUNTAP interface to create TAP network interfaces to an encrypted virtual
LAN. Members of a community share encryption keys which allow exchange of
data. The supernode is used for peer discovery and initial packet relay before
direct peer-to-peer exchange is established. Once direct packet exchange is
established, the supernode is not required.
N2N-2 introduces additional security features and multiple supernodes.
%prep
%setup -q
echo -e "\n *** Building ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION}-${RPM_PACKAGE_RELEASE} ***\n"
%build
make
%install
make PREFIX=${RPM_BUILD_ROOT}/usr install
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
/usr/sbin/supernode
/usr/sbin/edge
%doc /usr/share/man/man1/supernode.1.gz
%doc /usr/share/man/man8/edge.8.gz
%doc /usr/share/man/man7/n2n_v2.7.gz
%changelog
* Fri Oct 30 2009 Richard Andrews <andrews@ntop.org> -
- First beta for n2n-2
* Sat May 3 2008 Richard Andrews <andrews@ntop.org> -
- Initial build.

203
n2n_keyfile.c Normal file
View File

@ -0,0 +1,203 @@
/* (c) 2009 Richard Andrews <andrews@ntop.org> */
/* Contributions from:
* - Jozef Kralik
*/
#include "n2n.h"
#include "n2n_keyfile.h"
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#ifdef WIN32
char *strsep( char **ppsz_string, const char *psz_delimiters )
{
char *p;
char *psz_string = *ppsz_string;
if( !psz_string )
return NULL;
p = strpbrk( psz_string, psz_delimiters );
if( !p )
{
*ppsz_string = NULL;
return psz_string;
}
*p++ = '\0';
*ppsz_string = p;
return psz_string;
}
#endif
/* Parse hex nibbles in ascii until a non-nibble character is found. Nibble
* characters are 0-9, a-f and A-F.
*
* Return number of bytes parsed into keyBuf or a negative error code.
*/
ssize_t n2n_parse_hex( uint8_t * keyBuf,
size_t keyLen,
const char * textKey,
size_t textLen)
{
ssize_t retval=0;
uint8_t * pout=keyBuf;
size_t octet=0;
const char * textEnd;
const char * pbeg;
textEnd = textKey+textLen;
pbeg=textKey;
while ( ( pbeg + 1 < textEnd ) && ( retval < (ssize_t)keyLen ) )
{
if ( 1 != sscanf( pbeg, "%02x", (unsigned int*)&octet ) )
{
retval=-1;
break;
}
*pout = (octet & 0xff);
++pout;
++retval;
pbeg += 2;
}
return retval;
}
static int parseKeyLine( n2n_cipherspec_t * spec,
const char * linein )
{
/* parameters are separated by whitespace */
char line[N2N_KEYFILE_LINESIZE];
char * lp=line;
const char * token;
strncpy( line, linein, N2N_KEYFILE_LINESIZE );
memset( spec, 0, sizeof( n2n_cipherspec_t ) );
/* decode valid_from time */
token = strsep( &lp, DELIMITERS );
if ( !token ) { goto error; }
spec->valid_from = atol(token);
/* decode valid_until time */
token = strsep( &lp, DELIMITERS );
if ( !token ) { goto error; }
spec->valid_until = atol(token);
/* decode the transform number */
token = strsep( &lp, DELIMITERS );
if ( !token ) { goto error; }
spec->t = atoi(token);
/* The reset if opaque key data */
token = strsep( &lp, DELIMITERS );
if ( !token ) { goto error; }
strncpy( (char *)spec->opaque, token, N2N_MAX_KEYSIZE );
spec->opaque_size=strlen( (char *)spec->opaque);
return 0;
error:
return -1;
}
#define SEP "/"
int validCipherSpec( const n2n_cipherspec_t * k,
time_t now )
{
if ( k->valid_until < k->valid_from ) { goto bad; }
if ( k->valid_from > now ) { goto bad; }
if ( k->valid_until < now ) { goto bad; }
return 0;
bad:
return -1;
}
/* Read key control file and return the number of specs stored or a negative
* error code.
*
* As the specs are read in the from and until time values are compared to
* present time. Only those keys which are valid are stored.
*/
int n2n_read_keyfile( n2n_cipherspec_t * specs, /* fill out this array of cipherspecs */
size_t numspecs, /* number of slots in the array. */
const char * ctrlfile_path ) /* path to control file */
{
/* Each line contains one cipherspec. */
int retval=0;
FILE * fp=NULL;
size_t idx=0;
time_t now = time(NULL);
traceEvent( TRACE_DEBUG, "Reading '%s'\n", ctrlfile_path );
fp = fopen( ctrlfile_path, "r" );
if ( fp )
{
/* Read the file a line a time with fgets. */
char line[N2N_KEYFILE_LINESIZE];
size_t lineNum=0;
while ( idx < numspecs )
{
n2n_cipherspec_t * k = &(specs[idx]);
fgets( line, N2N_KEYFILE_LINESIZE, fp );
++lineNum;
if ( strlen(line) > 1 )
{
if ( 0 == parseKeyLine( k, line ) )
{
if ( k->valid_until > now )
{
traceEvent( TRACE_INFO, " --> [%u] from %lu, until %lu, transform=%hu, data=%s\n",
idx, k->valid_from, k->valid_until, k->t, k->opaque );
++retval;
++idx;
}
else
{
traceEvent( TRACE_INFO, " --X [%u] from %lu, until %lu, transform=%hu, data=%s\n",
idx, k->valid_from, k->valid_until, k->t, k->opaque );
}
}
else
{
traceEvent( TRACE_WARNING, "Failed to decode line %u\n", lineNum );
}
}
if ( feof(fp) )
{
break;
}
line[0]=0; /* this line has been consumed */
}
fclose( fp);
fp=NULL;
}
else
{
traceEvent( TRACE_ERROR, "Failed to open '%s'\n", ctrlfile_path );
retval = -1;
}
return retval;
}

101
n2n_keyfile.h Normal file
View File

@ -0,0 +1,101 @@
/* (c) 2009 Richard Andrews <andrews@ntop.org> */
/** Key files
*
* Edge implements a very simple interface for getting instructions about
* rolling keys.
*
* Key definitions are written as individual files in <transform>/<sa>.key. The
* format of each key is a single line of hex nibbles as follows:
*
* 0102030405060708090a0b0c0d0e0f
*
* Any external key exchange mechanism can receive the key data write it into
* the keyfiles.
*
* To control which keys are active at what times the key control file is
* used. This is a single file which is periodically reread. It contains key
* definitions in chronological order with one line per key definition as
* follows:
*
* <valid_from> <valid_until> <transform> <opaque>
*
* edge reads the key control file periodically to get updates in policy. edge
* holds a number of keys in memory. Data can be decoded if it was encoded by
* any of the keys still in memory. By having at least 2 keys in memory it
* allows for clock skew and transmission delay when encoder and decoder roll
* keys at slightly different times. The amount of overlap in the valid time
* ranges provides the tolerance to timing skews in the system.
*
* The keys have the same level of secrecy as any other user file. Existing
* UNIX permission systems can be used to provide access controls.
*
*/
/** How Edge Uses The Key Schedule
*
* Edge provides state space for a number of transform algorithms. Each
* transform uses its state space to store the SA information for its keys as
* found in the key file. When a packet is received the transform ID is in
* plain text. The packets is then sent to that transform for decoding. Each
* transform can store its SA numbers differently (or not at all). The
* transform code then finds the SA number, then finds the cipher (with key) in
* the state space and uses this to decode the packet.
*
* To support this, as edge reads each key line, it passes it to the
* appropriate transform to parse the line and store the SA information in its
* state space.
*
* When encoding a packet, edge has several transforms and potentially valid
* SAs to choose from. To keep track of which one to use for encoding edge does
* its own book-keeping as each key line is passed to the transform code: it
* stores a lookup of valid_from -> transform. When encoding a packet it then
* just calls the transform with the best valid_from in the table. The
* transform's own state space has all the SAs for its keys and the best of
* those is chosen.
*/
#if !defined( N2N_KEYFILE_H_ )
#define N2N_KEYFILE_H_
#include "n2n_wire.h"
#include <time.h>
#define N2N_MAX_KEYSIZE 256 /* bytes */
#define N2N_MAX_NUM_CIPHERSPECS 8
#define N2N_KEYPATH_SIZE 256
#define N2N_KEYFILE_LINESIZE 256
/** This structure stores an encryption cipher spec. */
struct n2n_cipherspec
{
n2n_transform_t t; /* N2N_TRANSFORM_ID_xxx for this spec. */
time_t valid_from; /* Start using the key at this time. */
time_t valid_until; /* Key is valid if time < valid_until. */
uint16_t opaque_size; /* Size in bytes of key. */
uint8_t opaque[N2N_MAX_KEYSIZE];/* Key matter. */
};
typedef struct n2n_cipherspec n2n_cipherspec_t;
static const char * const DELIMITERS=" \t\n\r";
/** @return number of cipherspec items filled. */
int n2n_read_keyfile( n2n_cipherspec_t * specs, /* fill out this array of cipherspecs */
size_t numspecs, /* number of slots in the array. */
const char * ctrlfile_path ); /* path to control file */
int validCipherSpec( const n2n_cipherspec_t * k,
time_t now );
ssize_t n2n_parse_hex( uint8_t * keyBuf,
size_t keyMax,
const char * textKey,
size_t textLen );
/*----------------------------------------------------------------------------*/
#endif /* #if !defined( N2N_KEYFILE_H_ ) */

78
n2n_transforms.h Normal file
View File

@ -0,0 +1,78 @@
/* (c) 2009 Richard Andrews <andrews@ntop.org> */
#if !defined(N2N_TRANSFORMS_H_)
#define N2N_TRANSFORMS_H_
#include "n2n_keyfile.h"
#include "n2n_wire.h"
#define N2N_TRANSFORM_ID_INVAL 0 /* marks uninitialised data */
#define N2N_TRANSFORM_ID_NULL 1
#define N2N_TRANSFORM_ID_TWOFISH 2
#define N2N_TRANSFORM_ID_AESCBC 3
#define N2N_TRANSFORM_ID_LZO 4
#define N2N_TRANSFORM_ID_TWOFISH_LZO 5
#define N2N_TRANSFORM_ID_AESCBC_LZO 6
#define N2N_TRANSFORM_ID_USER_START 64
#define N2N_TRANSFORM_ID_MAX 65535
struct n2n_trans_op;
typedef struct n2n_trans_op n2n_trans_op_t;
struct n2n_tostat
{
uint8_t can_tx; /* Does this transop have a valid SA for encoding. */
n2n_cipherspec_t tx_spec; /* If can_tx, the spec used to encode. */
};
typedef struct n2n_tostat n2n_tostat_t;
typedef int (*n2n_transdeinit_f)( n2n_trans_op_t * arg );
typedef int (*n2n_transaddspec_f)( n2n_trans_op_t * arg,
const n2n_cipherspec_t * cspec );
typedef n2n_tostat_t (*n2n_transtick_f)( n2n_trans_op_t * arg,
time_t now );
typedef int (*n2n_transform_f)( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len );
/** Holds the info associated with a data transform plugin.
*
* When a packet arrives the transform ID is extracted. This defines the code
* to use to decode the packet content. The transform code then decodes the
* packet and consults its internal key lookup.
*/
struct n2n_trans_op
{
void * priv; /* opaque data. Key schedule goes here. */
n2n_transform_t transform_id; /* link header enum to a transform */
size_t tx_cnt;
size_t rx_cnt;
n2n_transdeinit_f deinit; /* destructor function */
n2n_transaddspec_f addspec; /* parse opaque data from a key schedule file. */
n2n_transtick_f tick; /* periodic maintenance */
n2n_transform_f fwd; /* encode a payload */
n2n_transform_f rev; /* decode a payload */
};
/* Setup a single twofish SA for single-key operation. */
int transop_twofish_setup( n2n_trans_op_t * ttt,
n2n_sa_t sa_num,
uint8_t * encrypt_pwd,
uint32_t encrypt_pwd_len );
/* Initialise an empty transop ready to receive cipherspec elements. */
int transop_twofish_init( n2n_trans_op_t * ttt );
int transop_aes_init( n2n_trans_op_t * ttt );
void transop_null_init( n2n_trans_op_t * ttt );
#endif /* #if !defined(N2N_TRANSFORMS_H_) */

156
n2n_v2.7 Normal file
View File

@ -0,0 +1,156 @@
.TH "n2n_v2" 7 "Sep 21, 2009" "revision 3909" "Background"
.SH NAME
N2n Version 2 \- version 2 of the n2n decentralised peer-to-peer network overlay
VPN.
.SH DESCRIPTION
N2n is a peer-to-peer network overlay or VPN system that provides layer 2 over
layer 3 encapsulation with data transform capabilities such as encryption and
compression. This guide discusses the differences of version 2 or n2n from
version 1.
.SH PROTOCOLS
N2n-2 uses a different set of messages to communicate with edges and
supernodes. The n2n-2 messages are not compatible with n2n-1. There is no
backward compatibility for n2n-1.
.SH ENCRYPTION
N2n-2 offers a new way of handling encryption compared to n2n-1. N2n-1 provided
facility for a single community password with no expiration. In n2n-2 this
method is preserved but a new mechanism has been added using a key schedule
file.
.TP
Key Schedule
A key schedule file lists a number of keys with the period for which each is
valid along with the encryption type identifier and the actual key value. This
allows the user to define up to 32 keys in advance with a pre-set time at which
they keys will change. The key schedule file can be reloaded while the edge is
running to allow new keys to be loaded and unused keys expunged.
.TP
Timing Requirements When a key rolls over to the next in the schedule, the new
key is used for all transmitted packets; however any packets received using an
older key can still be decoded as the keys from the key schedule are still
known. As a result edges do not need to have accurate time synchronisation. The
accuracy of required synchronisation depends to a large degree on the key
schedule. Rapid key roll-overs requires more accurate time synchronisation.
.P
N2n-2 provides the following encryption ciphers; more can be added as required:
.TP
.B (1) NULL
Data is encapsulated unchanged. Useful for testing and high-performance, low
sensitivity applications.
.TP
.B (2) TF
Twofish AES candidate.
.P
The following additional ciphers are specified but not yet implemented:
.TP
.B (3) AES-CBC
AES in CBC mode with 256-bit key.
.TP
.B (4) LZO
LZO compression of data (no encryption).
.TP
.B (5) TF-LZO
TF cipher with LZO compression of data prior to encryption.
.TP
.B (6) AES-CBC-LZO
AES-CBC ciper with LZO compression of data prior to encryption.
.SH EXTENSIBILITY
N2n-2 decouples the data transform system from the core of the edge
operation. This allows for easier addition of new data transform
operations. N2n-2 reserves 64 standard transform identifiers (such as TwoFish
encryption) but allocates transform identifiers 64 - 65536 for user-defined
transforms. This allows anyone to add to n2n new private transforms without
breaking compatibility with the standard offering.
.SH MULTIPLE SUPERNODES
N2n-2 introduces the capability of multiple supernodes to be used by an
edge. N2n-2 offers supernode in several flavours:
.TP
Stand-alone supernode
This is the same concept as from n2n-1. Supernode is a small efficient C program
which operates in isolation.
.TP
Federated supernodes
This is a cluster of supernodes which share information. Edges registered to any
of the cooperating supernodes can relay packets through the supernode federation
and switch supernodes if required. Supernodes can send PACKET or REGISTER
messages to other supernodes to try and find the destination edge.
.P
The n2n-2 edge implementation allows multiple supernodes to be specified on the
command line. Edges monitor the current supernode for responses to
REGISTER_SUPER messages. If 3 responses are missed then the edge starts looking
for a new supernode. It cycles through the list of supernodes specified until it
finds a working one.
.SH EFFICIENCY
The n2n-2 message formats have been made more efficient. The amount of data
overhead has been reduced by ensuring the messages contain only the data fields
required. Some optional fields do not consume data if they are not present.
.SH DAEMON OPERATION
The supernode and edge use daemon mode of operation by default. This sense is
inverted from n2n-1 where they ran in the foreground by default. They can be
made to run in the foreground so tools such a DJB's daemontools can work with
them. See the
.B -f
option
.SH MANAGEMENT CONSOLE
Edge and supernode in n2n-2 provide a UDP-based management console. Both listen
on the localhost address 127.0.0.1. Commands can be sent to the programs by
sending to the UDP socket. Responses are returned to the socket from which
commands were issued. This only works from the computer on which the programs
are running. Statistics can be retrieved and commands issued. The netcat utility
is all that is required; but more sophisticated tools could be built on the
interface.
.SH SUPERNODE AUTHENTICATION
.B (To be implemented)
Space has been reserved in the supernode registration messages for an
authentication mechanism.
.SH MESSAGE SUMMARY
The following message types work within n2n-2.
.TP
REGISTER_SUPER
Sent from an edge to its local supernode to register its MAC with the community.
.TP
REGISTER_SUPER_ACK
Sent from a supernode to an edge to confirm registration. This also carries the
definition of the edge socket as seen at the supernode so NAT can be detected
and described.
.TP
REGISTER_SUPER_NAK
Supernode refusing to register an edge.
.TP
PACKET
Encapsulated ethernet packets sent between edges. Supernodes forward or
broadcast these and edges send them direct in peer-to-peer mode.
.TP
REGISTER
A peer-to-peer mode registration request from one edge to another. Supernodes
forward these to facilitate NAT crossing introductions.
.TP
REGISTER_ACK
Complete peer-to-peer mode setup between two edges. These messages need to
travel direct between edges.
.TP
FEDERATION
Federated supernodes exchanging community information.
.SH OTHER DIFFERENCES
.TP
HTTP Tunneling
This experimental feature (-t option in n2n_v1) of n2n_v1 has been removed
entirely from n2n_v2.
.SH AUTHORS
.TP
Richard Andrews andrews (at) ntop.org - main author of n2n-2
.TP
Luca Deri
deri (at) ntop.org - code inherited from n2n-1
.SH SEE ALSO
ifconfig(8) edge(8) supernode(1)

321
n2n_wire.h Normal file
View File

@ -0,0 +1,321 @@
/* (c) 2009 Richard Andrews <andrews@ntop.org>
*
* Contributions by:
* Luca Deri
* Lukasz Taczuk
*/
#if !defined( N2N_WIRE_H_ )
#define N2N_WIRE_H_
#include <stdlib.h>
#if defined(WIN32)
#include "win32/n2n_win32.h"
#if defined(__MINGW32__)
#include <stdint.h>
#endif /* #ifdef __MINGW32__ */
#else /* #if defined(WIN32) */
#include <stdint.h>
#include <netinet/in.h>
#include <sys/socket.h> /* AF_INET and AF_INET6 */
#endif /* #if defined(WIN32) */
#define N2N_PKT_VERSION 2
#define N2N_DEFAULT_TTL 2 /* can be forwarded twice at most */
#define N2N_COMMUNITY_SIZE 16
#define N2N_MAC_SIZE 6
#define N2N_COOKIE_SIZE 4
#define N2N_PKT_BUF_SIZE 2048
#define N2N_SOCKBUF_SIZE 64 /* string representation of INET or INET6 sockets */
typedef uint8_t n2n_community_t[N2N_COMMUNITY_SIZE];
typedef uint8_t n2n_mac_t[N2N_MAC_SIZE];
typedef uint8_t n2n_cookie_t[N2N_COOKIE_SIZE];
typedef char n2n_sock_str_t[N2N_SOCKBUF_SIZE]; /* tracing string buffer */
enum n2n_pc
{
n2n_ping=0, /* Not used */
n2n_register=1, /* Register edge to edge */
n2n_deregister=2, /* Deregister this edge */
n2n_packet=3, /* PACKET data content */
n2n_register_ack=4, /* ACK of a registration from edge to edge */
n2n_register_super=5, /* Register edge to supernode */
n2n_register_super_ack=6, /* ACK from supernode to edge */
n2n_register_super_nak=7, /* NAK from supernode to edge - registration refused */
n2n_federation=8 /* Not used by edge */
};
typedef enum n2n_pc n2n_pc_t;
#define N2N_FLAGS_OPTIONS 0x0080
#define N2N_FLAGS_SOCKET 0x0040
#define N2N_FLAGS_FROM_SUPERNODE 0x0020
/* The bits in flag that are the packet type */
#define N2N_FLAGS_TYPE_MASK 0x001f /* 0 - 31 */
#define N2N_FLAGS_BITS_MASK 0xffe0
#define IPV4_SIZE 4
#define IPV6_SIZE 16
#define N2N_AUTH_TOKEN_SIZE 32 /* bytes */
#define N2N_EUNKNOWN -1
#define N2N_ENOTIMPL -2
#define N2N_EINVAL -3
#define N2N_ENOSPACE -4
typedef uint16_t n2n_flags_t;
typedef uint16_t n2n_transform_t; /* Encryption, compression type. */
typedef uint32_t n2n_sa_t; /* security association number */
struct n2n_sock
{
uint8_t family; /* AF_INET or AF_INET6; or 0 if invalid */
uint16_t port; /* host order */
union
{
uint8_t v6[IPV6_SIZE]; /* byte sequence */
uint8_t v4[IPV4_SIZE]; /* byte sequence */
} addr;
};
typedef struct n2n_sock n2n_sock_t;
struct n2n_auth
{
uint16_t scheme; /* What kind of auth */
uint16_t toksize; /* Size of auth token */
uint8_t token[N2N_AUTH_TOKEN_SIZE]; /* Auth data interpreted based on scheme */
};
typedef struct n2n_auth n2n_auth_t;
struct n2n_common
{
/* int version; */
uint8_t ttl;
n2n_pc_t pc;
n2n_flags_t flags;
n2n_community_t community;
};
typedef struct n2n_common n2n_common_t;
struct n2n_REGISTER
{
n2n_cookie_t cookie; /* Link REGISTER and REGISTER_ACK */
n2n_mac_t srcMac; /* MAC of registering party */
n2n_mac_t dstMac; /* MAC of target edge */
n2n_sock_t sock; /* REVISIT: unused? */
};
typedef struct n2n_REGISTER n2n_REGISTER_t;
struct n2n_REGISTER_ACK
{
n2n_cookie_t cookie; /* Return cookie from REGISTER */
n2n_mac_t srcMac; /* MAC of acknowledging party (supernode or edge) */
n2n_mac_t dstMac; /* Reflected MAC of registering edge from REGISTER */
n2n_sock_t sock; /* Supernode's view of edge socket (IP Addr, port) */
};
typedef struct n2n_REGISTER_ACK n2n_REGISTER_ACK_t;
struct n2n_PACKET
{
n2n_mac_t srcMac;
n2n_mac_t dstMac;
n2n_sock_t sock;
n2n_transform_t transform;
};
typedef struct n2n_PACKET n2n_PACKET_t;
/* Linked with n2n_register_super in n2n_pc_t. Only from edge to supernode. */
struct n2n_REGISTER_SUPER
{
n2n_cookie_t cookie; /* Link REGISTER_SUPER and REGISTER_SUPER_ACK */
n2n_mac_t edgeMac; /* MAC to register with edge sending socket */
n2n_auth_t auth; /* Authentication scheme and tokens */
};
typedef struct n2n_REGISTER_SUPER n2n_REGISTER_SUPER_t;
/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */
struct n2n_REGISTER_SUPER_ACK
{
n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */
n2n_mac_t edgeMac; /* MAC registered to edge sending socket */
uint16_t lifetime; /* How long the registration will live */
n2n_sock_t sock; /* Sending sockets associated with edgeMac */
/* The packet format provides additional supernode definitions here.
* uint8_t count, then for each count there is one
* n2n_sock_t.
*/
uint8_t num_sn; /* Number of supernodes that were send
* even if we cannot store them all. If
* non-zero then sn_bak is valid. */
n2n_sock_t sn_bak; /* Socket of the first backup supernode */
};
typedef struct n2n_REGISTER_SUPER_ACK n2n_REGISTER_SUPER_ACK_t;
/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */
struct n2n_REGISTER_SUPER_NAK
{
n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */
};
typedef struct n2n_REGISTER_SUPER_NAK n2n_REGISTER_SUPER_NAK_t;
struct n2n_buf
{
uint8_t * data;
size_t size;
};
typedef struct n2n_buf n2n_buf_t;
int encode_uint8( uint8_t * base,
size_t * idx,
const uint8_t v );
int decode_uint8( uint8_t * out,
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_uint16( uint8_t * base,
size_t * idx,
const uint16_t v );
int decode_uint16( uint16_t * out,
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_uint32( uint8_t * base,
size_t * idx,
const uint32_t v );
int decode_uint32( uint32_t * out,
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_buf( uint8_t * base,
size_t * idx,
const void * p,
size_t s);
int decode_buf( uint8_t * out,
size_t bufsize,
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_mac( uint8_t * base,
size_t * idx,
const n2n_mac_t m );
int decode_mac( uint8_t * out, /* of size N2N_MAC_SIZE. This clearer than passing a n2n_mac_t */
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_common( uint8_t * base,
size_t * idx,
const n2n_common_t * common );
int decode_common( n2n_common_t * out,
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_sock( uint8_t * base,
size_t * idx,
const n2n_sock_t * sock );
int decode_sock( n2n_sock_t * sock,
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_REGISTER( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_t * reg );
int decode_REGISTER( n2n_REGISTER_t * pkt,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_REGISTER_SUPER( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_SUPER_t * reg );
int decode_REGISTER_SUPER( n2n_REGISTER_SUPER_t * pkt,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_REGISTER_ACK( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_ACK_t * reg );
int decode_REGISTER_ACK( n2n_REGISTER_ACK_t * pkt,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx );
int encode_REGISTER_SUPER_ACK( uint8_t * base,
size_t * idx,
const n2n_common_t * cmn,
const n2n_REGISTER_SUPER_ACK_t * reg );
int decode_REGISTER_SUPER_ACK( n2n_REGISTER_SUPER_ACK_t * reg,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx );
int fill_sockaddr( struct sockaddr * addr,
size_t addrlen,
const n2n_sock_t * sock );
int encode_PACKET( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_PACKET_t * pkt );
int decode_PACKET( n2n_PACKET_t * pkt,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx );
#endif /* #if !defined( N2N_WIRE_H_ ) */

55
openwrt/kamikaze/Makefile Normal file
View File

@ -0,0 +1,55 @@
#
# Copyright (C) 2008 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
include $(TOPDIR)/rules.mk
PKG_BRANCH:=trunk
PKG_SOURCE_URL:=https://svn.ntop.org/svn/ntop/trunk/n2n
PKG_REV:=$(shell LC_ALL=C svn info ${PKG_SOURCE_URL} | sed -ne's/^Last Changed Rev: //p')
PKG_NAME:=n2n
PKG_VERSION:=svn$(PKG_REV)
PKG_RELEASE:=1
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.gz
PKG_SOURCE_PROTO:=svn
PKG_SOURCE_VERSION:=$(PKG_REV)
PKG_BUILD_DEPENDS:=
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_INSTALL_DIR:=$(PKG_BUILD_DIR)
include $(INCLUDE_DIR)/package.mk
define Package/n2n
SECTION:=net
CATEGORY:=Network
TITLE:=VPN tunneling daemon
URL:=http://www.ntop.org/n2n/
SUBMENU:=VPN
DEPENDS:=libpthread
endef
define Build/Configure
endef
define Build/Compile
$(MAKE) CC="$(TARGET_CC)" -C $(PKG_BUILD_DIR)
endef
define Package/n2n/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/edge $(1)/usr/sbin/
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/supernode $(1)/usr/sbin/
endef
$(eval $(call BuildPackage,n2n))

30
scripts/mk_SRPM.sh Executable file
View File

@ -0,0 +1,30 @@
#!/bin/sh
# This script makes a SRPM - a source RPM file which can be built into the
# appropriate distro specific RPM for any platform.
#
# To build the binary package:
# rpm -i n2n-<ver>.src.rpm
# rpmbuild -bb n2n.spec
#
# Look for the "Wrote:" line to see where the final RPM is.
#
# To run this script cd to the n2n directory and run it as follows
# scripts/mk_SRPMS.sh
#
set -e
set -x
BASE=`pwd`
TARFILE=`${BASE}/scripts/mk_tar.sh`
test -f ${TARFILE}
echo "Building SRPM"
# -ts means build source RPM from tarfile
rpmbuild -ts ${TARFILE}
echo "Done"

46
scripts/mk_deb.sh Executable file
View File

@ -0,0 +1,46 @@
#!/bin/bash
# This script makes a SRPM - a source RPM file which can be built into the
# appropriate distro specific RPM for any platform.
#
# To build the binary package:
# rpm -i n2n-<ver>.src.rpm
# rpmbuild -bb n2n.spec
#
# Look for the "Wrote:" line to see where the final RPM is.
#
# To run this script cd to the n2n directory and run it as follows
# scripts/mk_SRPMS.sh
#
set -e
set -x
BASE=`pwd`
TARFILE=`${BASE}/scripts/mk_tar.sh`
TEMPDIR="build_deb"
test -f ${TARFILE}
echo "Building .deb"
if [ -d ${TEMPDIR} ]; then
echo "Removing ${TEMPDIR} directory"
rm -rf ${TEMPDIR} >&2
fi
mkdir ${TEMPDIR}
pushd ${TEMPDIR}
tar xzf ${TARFILE} #At original location
cd n2n*
dpkg-buildpackage -rfakeroot
popd
echo "Done"

116
scripts/mk_tar.sh Executable file
View File

@ -0,0 +1,116 @@
#!/bin/bash
# This script makes a SRPM - a source RPM file which can be built into the
# appropriate distro specific RPM for any platform.
#
# To build the binary package:
# rpm -i n2n-<ver>.src.rpm
# rpmbuild -bb n2n.spec
#
# Look for the "Wrote:" line to see where the final RPM is.
#
# To run this script cd to the n2n directory and run it as follows
# scripts/mk_SRPMS.sh
#
set -e
function exit_fail()
{
echo "$1"
exit 1
}
PACKAGE="n2n"
PKG_VERSION="2.1.0"
PKG_AND_VERSION="${PACKAGE}-${PKG_VERSION}"
TEMPDIR="tmp"
SOURCE_MANIFEST="
README
edge.c
lzoconf.h
lzodefs.h
Makefile
minilzo.c
minilzo.h
n2n.c
n2n.h
n2n_keyfile.c
n2n_keyfile.h
n2n.spec
n2n_transforms.h
n2n_wire.h
sn.c
transform_aes.c
transform_null.c
transform_tf.c
tuntap_linux.c
tuntap_freebsd.c
tuntap_netbsd.c
tuntap_osx.c
twofish.c
twofish.h
version.c
wire.c
edge.8
supernode.1
n2n_v2.7
debian/changelog
debian/compat
debian/control
debian/copyright
debian/n2n-edge.docs
debian/n2n-edge.install
debian/n2n-supernode.install
debian/n2n-edge.manpages
debian/n2n-supernode.manpages
debian/README.Debian
debian/rules
"
BASE=`pwd`
for F in ${SOURCE_MANIFEST}; do
test -e $F || exit_fail "Cannot find $F. Maybe you're in the wrong directory. Please execute from n2n directory."; >&2
done
echo "Found critical files. Proceeding." >&2
if [ -d ${TEMPDIR} ]; then
echo "Removing ${TEMPDIR} directory"
rm -rf ${TEMPDIR} >&2
fi
mkdir ${TEMPDIR} >&2
pushd ${TEMPDIR} >&2
echo "Creating staging directory ${PWD}/${PKG_AND_VERSION}" >&2
if [ -d ${PKG_AND_VERSION} ] ; then
echo "Removing ${PKG_AND_VERSION} directory"
rm -rf ${PKG_AND_VERSION} >&2
fi
mkdir ${PKG_AND_VERSION}
pushd ${BASE} >&2
echo "Copying in files" >&2
for F in ${SOURCE_MANIFEST}; do
cp --parents -a $F ${TEMPDIR}/${PKG_AND_VERSION}/
done
popd >&2
TARFILE="${PKG_AND_VERSION}.tar.gz"
echo "Creating ${TARFILE}" >&2
tar czf ${BASE}/${TARFILE} ${PKG_AND_VERSION}
popd >&2
rm -rf ${TEMPDIR} >&2
echo ${BASE}/${TARFILE}

793
sn.c Normal file
View File

@ -0,0 +1,793 @@
/* Supernode for n2n-2.x */
/* (c) 2009 Richard Andrews <andrews@ntop.org>
*
* Contributions by:
* Lukasz Taczuk
* Struan Bartlett
*/
#include "n2n.h"
#define N2N_SN_LPORT_DEFAULT 7654
#define N2N_SN_PKTBUF_SIZE 2048
#define N2N_SN_MGMT_PORT 5645
struct sn_stats
{
size_t errors; /* Number of errors encountered. */
size_t reg_super; /* Number of REGISTER_SUPER requests received. */
size_t reg_super_nak; /* Number of REGISTER_SUPER requests declined. */
size_t fwd; /* Number of messages forwarded. */
size_t broadcast; /* Number of messages broadcast to a community. */
time_t last_fwd; /* Time when last message was forwarded. */
time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */
};
typedef struct sn_stats sn_stats_t;
struct n2n_sn
{
time_t start_time; /* Used to measure uptime. */
sn_stats_t stats;
int daemon; /* If non-zero then daemonise. */
uint16_t lport; /* Local UDP port to bind to. */
int sock; /* Main socket for UDP traffic with edges. */
int mgmt_sock; /* management socket. */
struct peer_info * edges; /* Link list of registered edges. */
};
typedef struct n2n_sn n2n_sn_t;
static int try_forward( n2n_sn_t * sss,
const n2n_common_t * cmn,
const n2n_mac_t dstMac,
const uint8_t * pktbuf,
size_t pktsize );
static int try_broadcast( n2n_sn_t * sss,
const n2n_common_t * cmn,
const n2n_mac_t srcMac,
const uint8_t * pktbuf,
size_t pktsize );
/** Initialise the supernode structure */
static int init_sn( n2n_sn_t * sss )
{
#ifdef WIN32
initWin32();
#endif
memset( sss, 0, sizeof(n2n_sn_t) );
sss->daemon = 1; /* By defult run as a daemon. */
sss->lport = N2N_SN_LPORT_DEFAULT;
sss->sock = -1;
sss->mgmt_sock = -1;
sss->edges = NULL;
return 0; /* OK */
}
/** Deinitialise the supernode structure and deallocate any memory owned by
* it. */
static void deinit_sn( n2n_sn_t * sss )
{
if (sss->sock >= 0)
{
closesocket(sss->sock);
}
sss->sock=-1;
if ( sss->mgmt_sock >= 0 )
{
closesocket(sss->mgmt_sock);
}
sss->mgmt_sock=-1;
purge_peer_list( &(sss->edges), 0xffffffff );
}
/** Determine the appropriate lifetime for new registrations.
*
* If the supernode has been put into a pre-shutdown phase then this lifetime
* should not allow registrations to continue beyond the shutdown point.
*/
static uint16_t reg_lifetime( n2n_sn_t * sss )
{
return 120;
}
/** Update the edge table with the details of the edge which contacted the
* supernode. */
static int update_edge( n2n_sn_t * sss,
const n2n_mac_t edgeMac,
const n2n_community_t community,
const n2n_sock_t * sender_sock,
time_t now)
{
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
struct peer_info * scan;
traceEvent( TRACE_DEBUG, "update_edge for %s [%s]",
macaddr_str( mac_buf, edgeMac ),
sock_to_cstr( sockbuf, sender_sock ) );
scan = find_peer_by_mac( sss->edges, edgeMac );
if ( NULL == scan )
{
/* Not known */
scan = (struct peer_info*)calloc(1, sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */
memcpy(scan->community_name, community, sizeof(n2n_community_t) );
memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t));
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
/* insert this guy at the head of the edges list */
scan->next = sss->edges; /* first in list */
sss->edges = scan; /* head of list points to new scan */
traceEvent( TRACE_INFO, "update_edge created %s ==> %s",
macaddr_str( mac_buf, edgeMac ),
sock_to_cstr( sockbuf, sender_sock ) );
}
else
{
/* Known */
if ( (0 != memcmp(community, scan->community_name, sizeof(n2n_community_t))) ||
(0 != sock_equal(sender_sock, &(scan->sock) )) )
{
memcpy(scan->community_name, community, sizeof(n2n_community_t) );
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
traceEvent( TRACE_INFO, "update_edge updated %s ==> %s",
macaddr_str( mac_buf, edgeMac ),
sock_to_cstr( sockbuf, sender_sock ) );
}
else
{
traceEvent( TRACE_DEBUG, "update_edge unchanged %s ==> %s",
macaddr_str( mac_buf, edgeMac ),
sock_to_cstr( sockbuf, sender_sock ) );
}
}
scan->last_seen = now;
return 0;
}
/** Send a datagram to the destination embodied in a n2n_sock_t.
*
* @return -1 on error otherwise number of bytes sent
*/
static ssize_t sendto_sock(n2n_sn_t * sss,
const n2n_sock_t * sock,
const uint8_t * pktbuf,
size_t pktsize)
{
n2n_sock_str_t sockbuf;
if ( AF_INET == sock->family )
{
struct sockaddr_in udpsock;
udpsock.sin_family = AF_INET;
udpsock.sin_port = htons( sock->port );
memcpy( &(udpsock.sin_addr.s_addr), &(sock->addr.v4), IPV4_SIZE );
traceEvent( TRACE_DEBUG, "sendto_sock %lu to [%s]",
pktsize,
sock_to_cstr( sockbuf, sock ) );
return sendto( sss->sock, pktbuf, pktsize, 0,
(const struct sockaddr *)&udpsock, sizeof(struct sockaddr_in) );
}
else
{
/* AF_INET6 not implemented */
errno = EAFNOSUPPORT;
return -1;
}
}
/** Try to forward a message to a unicast MAC. If the MAC is unknown then
* broadcast to all edges in the destination community.
*/
static int try_forward( n2n_sn_t * sss,
const n2n_common_t * cmn,
const n2n_mac_t dstMac,
const uint8_t * pktbuf,
size_t pktsize )
{
struct peer_info * scan;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
scan = find_peer_by_mac( sss->edges, dstMac );
if ( NULL != scan )
{
int data_sent_len;
data_sent_len = sendto_sock( sss, &(scan->sock), pktbuf, pktsize );
if ( data_sent_len == pktsize )
{
++(sss->stats.fwd);
traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s",
pktsize,
sock_to_cstr( sockbuf, &(scan->sock) ),
macaddr_str(mac_buf, scan->mac_addr));
}
else
{
++(sss->stats.errors);
traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)",
pktsize,
sock_to_cstr( sockbuf, &(scan->sock) ),
macaddr_str(mac_buf, scan->mac_addr),
errno, strerror(errno) );
}
}
else
{
traceEvent( TRACE_DEBUG, "try_forward unknown MAC" );
/* Not a known MAC so drop. */
}
return 0;
}
/** Try and broadcast a message to all edges in the community.
*
* This will send the exact same datagram to zero or more edges registered to
* the supernode.
*/
static int try_broadcast( n2n_sn_t * sss,
const n2n_common_t * cmn,
const n2n_mac_t srcMac,
const uint8_t * pktbuf,
size_t pktsize )
{
struct peer_info * scan;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
traceEvent( TRACE_DEBUG, "try_broadcast" );
scan = sss->edges;
while(scan != NULL)
{
if( 0 == (memcmp(scan->community_name, cmn->community, sizeof(n2n_community_t)) )
&& (0 != memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) ) )
/* REVISIT: exclude if the destination socket is where the packet came from. */
{
int data_sent_len;
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
if(data_sent_len != pktsize)
{
++(sss->stats.errors);
traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s",
pktsize,
sock_to_cstr( sockbuf, &(scan->sock) ),
macaddr_str(mac_buf, scan->mac_addr),
strerror(errno));
}
else
{
++(sss->stats.broadcast);
traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s",
pktsize,
sock_to_cstr( sockbuf, &(scan->sock) ),
macaddr_str(mac_buf, scan->mac_addr));
}
}
scan = scan->next;
} /* while */
return 0;
}
static int process_mgmt( n2n_sn_t * sss,
const struct sockaddr_in * sender_sock,
const uint8_t * mgmt_buf,
size_t mgmt_size,
time_t now)
{
char resbuf[N2N_SN_PKTBUF_SIZE];
size_t ressize=0;
ssize_t r;
traceEvent( TRACE_DEBUG, "process_mgmt" );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"----------------\n" );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"uptime %lu\n", (now - sss->start_time) );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"edges %u\n",
(unsigned int)peer_list_size( sss->edges ) );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"errors %u\n",
(unsigned int)sss->stats.errors );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"reg_sup %u\n",
(unsigned int)sss->stats.reg_super );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"reg_nak %u\n",
(unsigned int)sss->stats.reg_super_nak );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"fwd %u\n",
(unsigned int) sss->stats.fwd );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"broadcast %u\n",
(unsigned int) sss->stats.broadcast );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"last fwd %lu sec ago\n",
(long unsigned int)(now - sss->stats.last_fwd) );
ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"last reg %lu sec ago\n",
(long unsigned int) (now - sss->stats.last_reg_super) );
r = sendto( sss->mgmt_sock, resbuf, ressize, 0/*flags*/,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
if ( r <= 0 )
{
++(sss->stats.errors);
traceEvent( TRACE_ERROR, "process_mgmt : sendto failed. %s", strerror(errno) );
}
return 0;
}
/** Examine a datagram and determine what to do with it.
*
*/
static int process_udp( n2n_sn_t * sss,
const struct sockaddr_in * sender_sock,
const uint8_t * udp_buf,
size_t udp_size,
time_t now)
{
n2n_common_t cmn; /* common fields in the packet header */
size_t rem;
size_t idx;
size_t msg_type;
uint8_t from_supernode;
macstr_t mac_buf;
macstr_t mac_buf2;
n2n_sock_str_t sockbuf;
traceEvent( TRACE_DEBUG, "process_udp(%lu)", udp_size );
/* Use decode_common() to determine the kind of packet then process it:
*
* REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK
*
* REGISTER, REGISTER_ACK and PACKET messages are forwarded to their
* destination edge. If the destination is not known then PACKETs are
* broadcast.
*/
rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */
idx = 0; /* marches through packet header as parts are decoded. */
if ( decode_common(&cmn, udp_buf, &rem, &idx) < 0 )
{
traceEvent( TRACE_ERROR, "Failed to decode common section" );
return -1; /* failed to decode packet */
}
msg_type = cmn.pc; /* packet code */
from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
if ( cmn.ttl < 1 )
{
traceEvent( TRACE_WARNING, "Expired TTL" );
return 0; /* Don't process further */
}
--(cmn.ttl); /* The value copied into all forwarded packets. */
if ( msg_type == MSG_TYPE_PACKET )
{
/* PACKET from one edge to another edge via supernode. */
/* pkt will be modified in place and recoded to an output of potentially
* different size due to addition of the socket.*/
n2n_PACKET_t pkt;
n2n_common_t cmn2;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0;
int unicast; /* non-zero if unicast */
const uint8_t * rec_buf; /* either udp_buf or encbuf */
sss->stats.last_fwd=now;
decode_PACKET( &pkt, &cmn, udp_buf, &rem, &idx );
unicast = (0 == is_multi_broadcast(pkt.dstMac) );
traceEvent( TRACE_DEBUG, "Rx PACKET (%s) %s -> %s %s",
(unicast?"unicast":"multicast"),
macaddr_str( mac_buf, pkt.srcMac ),
macaddr_str( mac_buf2, pkt.dstMac ),
(from_supernode?"from sn":"local") );
if ( !from_supernode )
{
memcpy( &cmn2, &cmn, sizeof( n2n_common_t ) );
/* We are going to add socket even if it was not there before */
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
pkt.sock.family = AF_INET;
pkt.sock.port = ntohs(sender_sock->sin_port);
memcpy( pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE );
rec_buf = encbuf;
/* Re-encode the header. */
encode_PACKET( encbuf, &encx, &cmn2, &pkt );
/* Copy the original payload unchanged */
encode_buf( encbuf, &encx, (udp_buf + idx), (udp_size - idx ) );
}
else
{
/* Already from a supernode. Nothing to modify, just pass to
* destination. */
traceEvent( TRACE_DEBUG, "Rx PACKET fwd unmodified" );
rec_buf = udp_buf;
encx = udp_size;
}
/* Common section to forward the final product. */
if ( unicast )
{
try_forward( sss, &cmn, pkt.dstMac, rec_buf, encx );
}
else
{
try_broadcast( sss, &cmn, pkt.srcMac, rec_buf, encx );
}
}/* MSG_TYPE_PACKET */
else if ( msg_type == MSG_TYPE_REGISTER )
{
/* Forwarding a REGISTER from one edge to the next */
n2n_REGISTER_t reg;
n2n_common_t cmn2;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0;
int unicast; /* non-zero if unicast */
const uint8_t * rec_buf; /* either udp_buf or encbuf */
sss->stats.last_fwd=now;
decode_REGISTER( &reg, &cmn, udp_buf, &rem, &idx );
unicast = (0 == is_multi_broadcast(reg.dstMac) );
if ( unicast )
{
traceEvent( TRACE_DEBUG, "Rx REGISTER %s -> %s %s",
macaddr_str( mac_buf, reg.srcMac ),
macaddr_str( mac_buf2, reg.dstMac ),
((cmn.flags & N2N_FLAGS_FROM_SUPERNODE)?"from sn":"local") );
if ( 0 != (cmn.flags & N2N_FLAGS_FROM_SUPERNODE) )
{
memcpy( &cmn2, &cmn, sizeof( n2n_common_t ) );
/* We are going to add socket even if it was not there before */
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
reg.sock.family = AF_INET;
reg.sock.port = ntohs(sender_sock->sin_port);
memcpy( reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE );
rec_buf = encbuf;
/* Re-encode the header. */
encode_REGISTER( encbuf, &encx, &cmn2, &reg );
/* Copy the original payload unchanged */
encode_buf( encbuf, &encx, (udp_buf + idx), (udp_size - idx ) );
}
else
{
/* Already from a supernode. Nothing to modify, just pass to
* destination. */
rec_buf = udp_buf;
encx = udp_size;
}
try_forward( sss, &cmn, reg.dstMac, rec_buf, encx ); /* unicast only */
}
else
{
traceEvent( TRACE_ERROR, "Rx REGISTER with multicast destination" );
}
}
else if ( msg_type == MSG_TYPE_REGISTER_ACK )
{
traceEvent( TRACE_DEBUG, "Rx REGISTER_ACK (NOT IMPLEMENTED) SHould not be via supernode" );
}
else if ( msg_type == MSG_TYPE_REGISTER_SUPER )
{
n2n_REGISTER_SUPER_t reg;
n2n_REGISTER_SUPER_ACK_t ack;
n2n_common_t cmn2;
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0;
/* Edge requesting registration with us. */
sss->stats.last_reg_super=now;
++(sss->stats.reg_super);
decode_REGISTER_SUPER( &reg, &cmn, udp_buf, &rem, &idx );
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_register_super_ack;
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
memcpy( &(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t) );
memcpy( ack.edgeMac, reg.edgeMac, sizeof(n2n_mac_t) );
ack.lifetime = reg_lifetime( sss );
ack.sock.family = AF_INET;
ack.sock.port = ntohs(sender_sock->sin_port);
memcpy( ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE );
ack.num_sn=0; /* No backup */
memset( &(ack.sn_bak), 0, sizeof(n2n_sock_t) );
traceEvent( TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]",
macaddr_str( mac_buf, reg.edgeMac ),
sock_to_cstr( sockbuf, &(ack.sock) ) );
update_edge( sss, reg.edgeMac, cmn.community, &(ack.sock), now );
encode_REGISTER_SUPER_ACK( ackbuf, &encx, &cmn2, &ack );
sendto( sss->sock, ackbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
traceEvent( TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]",
macaddr_str( mac_buf, reg.edgeMac ),
sock_to_cstr( sockbuf, &(ack.sock) ) );
}
return 0;
}
/** Help message to print if the command line arguments are not valid. */
static void exit_help(int argc, char * const argv[])
{
fprintf( stderr, "%s usage\n", argv[0] );
fprintf( stderr, "-l <lport>\tSet UDP main listen port to <lport>\n" );
#if defined(N2N_HAVE_DAEMON)
fprintf( stderr, "-f \tRun in foreground.\n" );
#endif /* #if defined(N2N_HAVE_DAEMON) */
fprintf( stderr, "-v \tIncrease verbosity. Can be used multiple times.\n" );
fprintf( stderr, "-h \tThis help message.\n" );
fprintf( stderr, "\n" );
exit(1);
}
static int run_loop( n2n_sn_t * sss );
/* *********************************************** */
static const struct option long_options[] = {
{ "foreground", no_argument, NULL, 'f' },
{ "local-port", required_argument, NULL, 'l' },
{ "help" , no_argument, NULL, 'h' },
{ "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
/** Main program entry point from kernel. */
int main( int argc, char * const argv[] )
{
n2n_sn_t sss;
init_sn( &sss );
{
int opt;
while((opt = getopt_long(argc, argv, "fl:vh", long_options, NULL)) != -1)
{
switch (opt)
{
case 'l': /* local-port */
sss.lport = atoi(optarg);
break;
case 'f': /* foreground */
sss.daemon = 0;
break;
case 'h': /* help */
exit_help(argc, argv);
break;
case 'v': /* verbose */
++traceLevel;
break;
}
}
}
#if defined(N2N_HAVE_DAEMON)
if (sss.daemon)
{
useSyslog=1; /* traceEvent output now goes to syslog. */
if ( -1 == daemon( 0, 0 ) )
{
traceEvent( TRACE_ERROR, "Failed to become daemon." );
exit(-5);
}
}
#endif /* #if defined(N2N_HAVE_DAEMON) */
traceEvent( TRACE_DEBUG, "traceLevel is %d", traceLevel);
sss.sock = open_socket(sss.lport, 1 /*bind ANY*/ );
if ( -1 == sss.sock )
{
traceEvent( TRACE_ERROR, "Failed to open main socket. %s", strerror(errno) );
exit(-2);
}
else
{
traceEvent( TRACE_NORMAL, "supernode is listening on UDP %u (main)", sss.lport );
}
sss.mgmt_sock = open_socket(N2N_SN_MGMT_PORT, 0 /* bind LOOPBACK */ );
if ( -1 == sss.mgmt_sock )
{
traceEvent( TRACE_ERROR, "Failed to open management socket. %s", strerror(errno) );
exit(-2);
}
else
{
traceEvent( TRACE_NORMAL, "supernode is listening on UDP %u (management)", N2N_SN_MGMT_PORT );
}
traceEvent(TRACE_NORMAL, "supernode started");
return run_loop(&sss);
}
/** Long lived processing entry point. Split out from main to simply
* daemonisation on some platforms. */
static int run_loop( n2n_sn_t * sss )
{
uint8_t pktbuf[N2N_SN_PKTBUF_SIZE];
int keep_running=1;
sss->start_time = time(NULL);
while(keep_running)
{
int rc;
ssize_t bread;
int max_sock;
fd_set socket_mask;
struct timeval wait_time;
time_t now=0;
FD_ZERO(&socket_mask);
max_sock = MAX(sss->sock, sss->mgmt_sock);
FD_SET(sss->sock, &socket_mask);
FD_SET(sss->mgmt_sock, &socket_mask);
wait_time.tv_sec = 10; wait_time.tv_usec = 0;
rc = select(max_sock+1, &socket_mask, NULL, NULL, &wait_time);
now = time(NULL);
if(rc > 0)
{
if (FD_ISSET(sss->sock, &socket_mask))
{
struct sockaddr_in sender_sock;
socklen_t i;
i = sizeof(sender_sock);
bread = recvfrom( sss->sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0/*flags*/,
(struct sockaddr *)&sender_sock, (socklen_t*)&i);
if ( bread < 0 ) /* For UDP bread of zero just means no data (unlike TCP). */
{
/* The fd is no good now. Maybe we lost our interface. */
traceEvent( TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno) );
keep_running=0;
break;
}
/* We have a datagram to process */
if ( bread > 0 )
{
/* And the datagram has data (not just a header) */
process_udp( sss, &sender_sock, pktbuf, bread, now );
}
}
if (FD_ISSET(sss->mgmt_sock, &socket_mask))
{
struct sockaddr_in sender_sock;
size_t i;
i = sizeof(sender_sock);
bread = recvfrom( sss->mgmt_sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0/*flags*/,
(struct sockaddr *)&sender_sock, (socklen_t*)&i);
if ( bread <= 0 )
{
traceEvent( TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno) );
keep_running=0;
break;
}
/* We have a datagram to process */
process_mgmt( sss, &sender_sock, pktbuf, bread, now );
}
}
else
{
traceEvent( TRACE_DEBUG, "timeout" );
}
purge_expired_registrations( &(sss->edges) );
} /* while */
deinit_sn( sss );
return 0;
}

43
supernode.1 Normal file
View File

@ -0,0 +1,43 @@
.TH supernode 1 "Jan 3, 2009" "revision 3679" "USER COMMANDS"
.SH NAME
supernode \- n2n supernode daemon
.SH SYNOPSIS
.B supernode \-l <port> [\-v]
.SH DESCRIPTION
N2N is a peer-to-peer VPN system. Supernode is a node introduction registry,
broadcast conduit and packet relay node for the n2n system. On startup supernode
begins listening on the specified UDP port for node registrations, and other
packets to route. The supernode can service any number of communities and routes
packets only between members of the same community. The supernode does not hold
the community encryption key and so cannot snoop or inject packets into the
community.
.PP
Supernode can service a number of n2n communities concurrently. Traffic does not
cross between communities.
.PP
All logging goes to stdout.
.SH OPTIONS
.TP
\-l <port>
listen on the given UDP port
.TP
\-v
use verbose logging
.TP
\-f
disable daemon mode (UNIX) and run in foreground.
.SH EXAMPLES
.TP
.B supernode -l 7654 -v
Start supernode listening on UDP port 7654 with verbose output.
.PP
.SH RESTART
When suprenode restarts it loses all registration information from associated
edge nodes. It can take up to five minutes for the edge nodes to re-register and
normal traffic flow to resume.
.SH EXIT STATUS
supernode is a daemon and any exit is an error
.SH AUTHOR
Luca Deri ( deri (at) ntop.org ), Richard Andrews ( andrews (at) ntop.org ), Don Bindner
.SH SEE ALSO
ifconfig(8) edge(8)

24
test.c Normal file
View File

@ -0,0 +1,24 @@
#include "n2n.h"
#include "n2n_keyfile.h"
#include <assert.h>
#include <stdio.h>
#include <sys/stat.h>
int main(int arc, const char * argv[] )
{
int e;
n2n_cipherspec_t specs[N2N_MAX_NUM_CIPHERSPECS];
e = n2n_read_keyfile( specs, N2N_MAX_NUM_CIPHERSPECS, "keyctrl.conf" );
if ( e < 0 )
{
perror( "Failed to read keyfile" );
}
else
{
fprintf( stderr, "Stored %d keys.\n", e );
}
return 0;
}

597
transform_aes.c Normal file
View File

@ -0,0 +1,597 @@
/* (c) 2009 Richard Andrews <andrews@ntop.org> */
/* Contributions from:
* - Jozef Kralik
*/
#include "n2n.h"
#include "n2n_transforms.h"
#if defined(N2N_HAVE_AES)
#include "openssl/aes.h"
#ifndef _MSC_VER
/* Not included in Visual Studio 2008 */
#include <strings.h> /* index() */
#endif
#define N2N_AES_NUM_SA 32 /* space for SAa */
#define N2N_AES_TRANSFORM_VERSION 1 /* version of the transform encoding */
#define N2N_AES_IVEC_SIZE 32 /* Enough space for biggest AES ivec */
typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE];
struct sa_aes
{
n2n_cipherspec_t spec; /* cipher spec parameters */
n2n_sa_t sa_id; /* security association index */
AES_KEY enc_key; /* tx key */
n2n_aes_ivec_t enc_ivec; /* tx CBC state */
AES_KEY dec_key; /* tx key */
n2n_aes_ivec_t dec_ivec; /* tx CBC state */
};
typedef struct sa_aes sa_aes_t;
/** Aes transform state data.
*
* With a key-schedule in place this will be populated with a number of
* SAs. Each SA has a lifetime and some opque data. The opaque data for aes
* consists of the SA number and key material.
*
*/
struct transop_aes
{
ssize_t tx_sa;
size_t num_sa;
sa_aes_t sa[N2N_AES_NUM_SA];
};
typedef struct transop_aes transop_aes_t;
static int transop_deinit_aes( n2n_trans_op_t * arg )
{
transop_aes_t * priv = (transop_aes_t *)arg->priv;
size_t i;
if ( priv )
{
/* Memory was previously allocated */
for (i=0; i<N2N_AES_NUM_SA; ++i )
{
sa_aes_t * sa = &(priv->sa[i]);
sa->sa_id=0;
}
priv->num_sa=0;
priv->tx_sa=-1;
free(priv);
}
arg->priv=NULL; /* return to fully uninitialised state */
return 0;
}
static size_t aes_choose_tx_sa( transop_aes_t * priv )
{
return priv->tx_sa; /* set in tick */
}
#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */
#define TRANSOP_AES_NONCE_SIZE 4
#define TRANSOP_AES_SA_SIZE 4
#define AES256_KEY_BYTES (256/8)
#define AES192_KEY_BYTES (192/8)
#define AES128_KEY_BYTES (128/8)
/* Return the best acceptable AES key size (in bytes) given an input keysize.
*
* The value returned will be one of AES128_KEY_BYTES, AES192_KEY_BYTES or
* AES256_KEY_BYTES.
*/
static size_t aes_best_keysize(size_t numBytes)
{
if (numBytes >= AES256_KEY_BYTES )
{
return AES256_KEY_BYTES;
}
else if (numBytes >= AES192_KEY_BYTES)
{
return AES192_KEY_BYTES;
}
else
{
return AES128_KEY_BYTES;
}
}
/** The aes packet format consists of:
*
* - a 8-bit aes encoding version in clear text
* - a 32-bit SA number in clear text
* - ciphertext encrypted from a 32-bit nonce followed by the payload.
*
* [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
* |<------ encrypted ------>|
*/
static int transop_encode_aes( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
int len2=-1;
transop_aes_t * priv = (transop_aes_t *)arg->priv;
uint8_t assembly[N2N_PKT_BUF_SIZE];
uint32_t * pnonce;
if ( (in_len + TRANSOP_AES_NONCE_SIZE) <= N2N_PKT_BUF_SIZE )
{
if ( (in_len + TRANSOP_AES_NONCE_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_VER_SIZE) <= out_len )
{
int len=-1;
size_t idx=0;
sa_aes_t * sa;
size_t tx_sa_num = 0;
/* The transmit sa is periodically updated */
tx_sa_num = aes_choose_tx_sa( priv );
sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
traceEvent( TRACE_DEBUG, "encode_aes %lu with SA %lu.", in_len, sa->sa_id );
/* Encode the aes format version. */
encode_uint8( outbuf, &idx, N2N_AES_TRANSFORM_VERSION );
/* Encode the security association (SA) number */
encode_uint32( outbuf, &idx, sa->sa_id );
/* Encrypt the assembly contents and write the ciphertext after the SA. */
len = in_len + TRANSOP_AES_NONCE_SIZE;
/* The assembly buffer is a source for encrypting data. The nonce is
* written in first followed by the packet payload. The whole
* contents of assembly are encrypted. */
pnonce = (uint32_t *)assembly;
*pnonce = rand();
memcpy( assembly + TRANSOP_AES_NONCE_SIZE, inbuf, in_len );
/* Need at least one encrypted byte at the end for the padding. */
len2 = ( (len / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* Round up to next whole AES adding at least one byte. */
assembly[ len2-1 ]=(len2-len);
traceEvent( TRACE_DEBUG, "padding = %u", assembly[ len2-1 ] );
memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
AES_cbc_encrypt( assembly, /* source */
outbuf + TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE, /* dest */
len2, /* enc size */
&(sa->enc_key), sa->enc_ivec, 1 /* encrypt */ );
len2 += TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE; /* size of data carried in UDP. */
}
else
{
traceEvent( TRACE_ERROR, "encode_aes outbuf too small." );
}
}
else
{
traceEvent( TRACE_ERROR, "encode_aes inbuf too big to encrypt." );
}
return len2;
}
/* Search through the array of SAs to find the one with the required ID.
*
* @return array index where found or -1 if not found
*/
static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id )
{
size_t i;
for (i=0; i < priv->num_sa; ++i)
{
const sa_aes_t * sa=NULL;
sa = &(priv->sa[i]);
if (req_id == sa->sa_id)
{
return i;
}
}
return -1;
}
/** The aes packet format consists of:
*
* - a 8-bit aes encoding version in clear text
* - a 32-bit SA number in clear text
* - ciphertext encrypted from a 32-bit nonce followed by the payload.
*
* [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
* |<------ encrypted ------>|
*/
static int transop_decode_aes( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
int len=0;
transop_aes_t * priv = (transop_aes_t *)arg->priv;
uint8_t assembly[N2N_PKT_BUF_SIZE];
if ( ( (in_len - (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */
&& (in_len >= (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_NONCE_SIZE) ) /* Has at least version, SA and nonce */
)
{
n2n_sa_t sa_rx;
ssize_t sa_idx=-1;
size_t rem=in_len;
size_t idx=0;
uint8_t aes_enc_ver=0;
/* Get the encoding version to make sure it is supported */
decode_uint8( &aes_enc_ver, inbuf, &rem, &idx );
if ( N2N_AES_TRANSFORM_VERSION == aes_enc_ver )
{
/* Get the SA number and make sure we are decrypting with the right one. */
decode_uint32( &sa_rx, inbuf, &rem, &idx );
sa_idx = aes_find_sa(priv, sa_rx);
if ( sa_idx >= 0 )
{
sa_aes_t * sa = &(priv->sa[sa_idx]);
traceEvent( TRACE_DEBUG, "decode_aes %lu with SA %lu.", in_len, sa_rx, sa->sa_id );
len = (in_len - (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE));
if ( 0 == (len % AES_BLOCK_SIZE ) )
{
uint8_t padding;
memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
AES_cbc_encrypt( (inbuf + TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE),
assembly, /* destination */
len,
&(sa->dec_key),
sa->dec_ivec, 0 /* decrypt */ );
/* last byte is how much was padding: max value should be
* AES_BLOCKSIZE-1 */
padding = assembly[ len-1 ] & 0xff;
if ( len >= (padding + TRANSOP_AES_NONCE_SIZE))
{
/* strictly speaking for this to be an ethernet packet
* it is going to need to be even bigger; but this is
* enough to prevent segfaults. */
traceEvent( TRACE_DEBUG, "padding = %u", padding );
len -= padding;
len -= TRANSOP_AES_NONCE_SIZE; /* size of ethernet packet */
/* Step over 4-byte random nonce value */
memcpy( outbuf,
assembly + TRANSOP_AES_NONCE_SIZE,
len );
}
else
{
traceEvent( TRACE_WARNING, "UDP payload decryption failed." );
}
}
else
{
traceEvent( TRACE_WARNING, "Encrypted length %d is not a multiple of AES_BLOCK_SIZE (%d)", len, AES_BLOCK_SIZE );
len = 0;
}
}
else
{
/* Wrong security association; drop the packet as it is undecodable. */
traceEvent( TRACE_ERROR, "decode_aes SA number %lu not found.", sa_rx );
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
}
}
else
{
/* Wrong security association; drop the packet as it is undecodable. */
traceEvent( TRACE_ERROR, "decode_aes unsupported aes version %u.", aes_enc_ver );
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
}
}
else
{
traceEvent( TRACE_ERROR, "decode_aes inbuf wrong size (%ul) to decrypt.", in_len );
}
return len;
}
static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
{
int retval = 1;
ssize_t pstat=-1;
transop_aes_t * priv = (transop_aes_t *)arg->priv;
uint8_t keybuf[N2N_MAX_KEYSIZE];
if ( priv->num_sa < N2N_AES_NUM_SA )
{
const char * op = (const char *)cspec->opaque;
const char * sep = index( op, '_' );
if ( sep )
{
char tmp[256];
size_t s;
s = sep - op;
memcpy( tmp, cspec->opaque, s );
tmp[s]=0;
s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
priv->sa[priv->num_sa].spec = *cspec;
priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
memset( keybuf, 0, N2N_MAX_KEYSIZE );
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
if ( pstat > 0 )
{
/* pstat is number of bytes read into keybuf. */
sa_aes_t * sa = &(priv->sa[priv->num_sa]);
size_t aes_keysize_bytes;
size_t aes_keysize_bits;
/* Clear out any old possibly longer key matter. */
memset( &(sa->enc_key), 0, sizeof(AES_KEY) );
memset( &(sa->dec_key), 0, sizeof(AES_KEY) );
memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
aes_keysize_bytes = aes_best_keysize(pstat);
aes_keysize_bits = 8 * aes_keysize_bytes;
/* Use N2N_MAX_KEYSIZE because the AES key needs to be of fixed
* size. If fewer bits specified then the rest will be
* zeroes. AES acceptable key sizes are 128, 192 and 256
* bits. */
AES_set_encrypt_key( keybuf, aes_keysize_bits, &(sa->enc_key));
AES_set_decrypt_key( keybuf, aes_keysize_bits, &(sa->dec_key));
/* Leave ivecs set to all zeroes */
traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits data=%s.\n",
priv->sa[priv->num_sa].sa_id, aes_keysize_bits, sep+1);
++(priv->num_sa);
retval = 0;
}
}
else
{
traceEvent( TRACE_ERROR, "transop_addspec_aes : bad key data - missing '_'.\n");
}
}
else
{
traceEvent( TRACE_ERROR, "transop_addspec_aes : full.\n");
}
return retval;
}
static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
{
transop_aes_t * priv = (transop_aes_t *)arg->priv;
size_t i;
int found=0;
n2n_tostat_t r;
memset( &r, 0, sizeof(r) );
traceEvent( TRACE_DEBUG, "transop_aes tick num_sa=%u now=%lu", priv->num_sa, now );
for ( i=0; i < priv->num_sa; ++i )
{
if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
{
time_t remaining = priv->sa[i].spec.valid_until - now;
traceEvent( TRACE_INFO, "transop_aes choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
priv->tx_sa=i;
found=1;
break;
}
else
{
traceEvent( TRACE_DEBUG, "transop_aes tick rejecting sa=%u %lu -> %lu",
priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
}
}
if ( 0==found)
{
traceEvent( TRACE_INFO, "transop_aes no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
}
else
{
r.can_tx = 1;
r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC;
r.tx_spec = priv->sa[priv->tx_sa].spec;
}
return r;
}
int transop_aes_init( n2n_trans_op_t * ttt )
{
int retval = 1;
transop_aes_t * priv = NULL;
if ( ttt->priv )
{
transop_deinit_aes( ttt );
}
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) );
if ( NULL != priv )
{
size_t i;
sa_aes_t * sa=NULL;
/* install the private structure. */
ttt->priv = priv;
priv->num_sa=0;
priv->tx_sa=0; /* We will use this sa index for encoding. */
ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
ttt->addspec = transop_addspec_aes;
ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
ttt->deinit = transop_deinit_aes;
ttt->fwd = transop_encode_aes;
ttt->rev = transop_decode_aes;
for(i=0; i<N2N_AES_NUM_SA; ++i)
{
sa = &(priv->sa[i]);
sa->sa_id=0;
memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
memset( &(sa->enc_key), 0, sizeof(AES_KEY) );
memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
memset( &(sa->dec_key), 0, sizeof(AES_KEY) );
memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
}
retval = 0;
}
else
{
memset( ttt, 0, sizeof(n2n_trans_op_t) );
traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
}
return retval;
}
#else /* #if defined(N2N_HAVE_AES) */
struct transop_aes
{
ssize_t tx_sa;
};
typedef struct transop_aes transop_aes_t;
static int transop_deinit_aes( n2n_trans_op_t * arg )
{
transop_aes_t * priv = (transop_aes_t *)arg->priv;
if ( priv )
{
free(priv);
}
arg->priv=NULL; /* return to fully uninitialised state */
return 0;
}
static int transop_encode_aes( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
return -1;
}
static int transop_decode_aes( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
return -1;
}
static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
{
traceEvent( TRACE_DEBUG, "transop_addspec_aes AES not built into edge.\n");
return -1;
}
static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
{
n2n_tostat_t r;
memset( &r, 0, sizeof(r) );
return r;
}
int transop_aes_init( n2n_trans_op_t * ttt )
{
int retval = 1;
transop_aes_t * priv = NULL;
if ( ttt->priv )
{
transop_deinit_aes( ttt );
}
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) );
if ( NULL != priv )
{
/* install the private structure. */
ttt->priv = priv;
priv->tx_sa=0; /* We will use this sa index for encoding. */
ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
ttt->addspec = transop_addspec_aes;
ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
ttt->deinit = transop_deinit_aes;
ttt->fwd = transop_encode_aes;
ttt->rev = transop_decode_aes;
retval = 0;
}
else
{
memset( ttt, 0, sizeof(n2n_trans_op_t) );
traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
}
return retval;
}
#endif /* #if defined(N2N_HAVE_AES) */

84
transform_null.c Normal file
View File

@ -0,0 +1,84 @@
/* (c) 2009 Richard Andrews <andrews@ntop.org> */
#include "n2n.h"
#include "n2n_transforms.h"
static int transop_deinit_null( n2n_trans_op_t * arg )
{
/* nothing to deallocate, nothing to release. */
return 0;
}
static int transop_encode_null( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
int retval = -1;
traceEvent( TRACE_DEBUG, "encode_null %lu", in_len );
if ( out_len >= in_len )
{
memcpy( outbuf, inbuf, in_len );
retval = in_len;
}
else
{
traceEvent( TRACE_DEBUG, "encode_null %lu too big for packet buffer", in_len );
}
return retval;
}
static int transop_decode_null( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
int retval = -1;
traceEvent( TRACE_DEBUG, "decode_null %lu", in_len );
if ( out_len >= in_len )
{
memcpy( outbuf, inbuf, in_len );
retval = in_len;
}
else
{
traceEvent( TRACE_DEBUG, "decode_null %lu too big for packet buffer", in_len );
}
return retval;
}
static int transop_addspec_null( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
{
return 0;
}
static n2n_tostat_t transop_tick_null( n2n_trans_op_t * arg, time_t now )
{
n2n_tostat_t r;
r.can_tx=1;
r.tx_spec.t = N2N_TRANSFORM_ID_NULL;
r.tx_spec.valid_from = 0;
r.tx_spec.valid_until = (time_t)(-1);
r.tx_spec.opaque_size=0;
return r;
}
void transop_null_init( n2n_trans_op_t * ttt )
{
memset(ttt, 0, sizeof(n2n_trans_op_t) );
ttt->transform_id = N2N_TRANSFORM_ID_NULL;
ttt->deinit = transop_deinit_null;
ttt->addspec = transop_addspec_null;
ttt->tick = transop_tick_null;
ttt->fwd = transop_encode_null;
ttt->rev = transop_decode_null;
}

487
transform_tf.c Normal file
View File

@ -0,0 +1,487 @@
/* (c) 2009 Richard Andrews <andrews@ntop.org> */
#include "n2n.h"
#include "n2n_transforms.h"
#include "twofish.h"
#ifndef _MSC_VER
/* Not included in Visual Studio 2008 */
#include <strings.h> /* index() */
#endif
#define N2N_TWOFISH_NUM_SA 32 /* space for SAa */
#define N2N_TWOFISH_TRANSFORM_VERSION 1 /* version of the transform encoding */
struct sa_twofish
{
n2n_cipherspec_t spec; /* cipher spec parameters */
n2n_sa_t sa_id; /* security association index */
TWOFISH * enc_tf; /* tx state */
TWOFISH * dec_tf; /* rx state */
};
typedef struct sa_twofish sa_twofish_t;
/** Twofish transform state data.
*
* With a key-schedule in place this will be populated with a number of
* SAs. Each SA has a lifetime and some opque data. The opaque data for twofish
* consists of the SA number and key material.
*
*/
struct transop_tf
{
ssize_t tx_sa;
size_t num_sa;
sa_twofish_t sa[N2N_TWOFISH_NUM_SA];
};
typedef struct transop_tf transop_tf_t;
static int transop_deinit_twofish( n2n_trans_op_t * arg )
{
transop_tf_t * priv = (transop_tf_t *)arg->priv;
size_t i;
if ( priv )
{
/* Memory was previously allocated */
for (i=0; i<N2N_TWOFISH_NUM_SA; ++i )
{
sa_twofish_t * sa = &(priv->sa[i]);
TwoFishDestroy(sa->enc_tf); /* deallocate TWOFISH */
sa->enc_tf=NULL;
TwoFishDestroy(sa->dec_tf); /* deallocate TWOFISH */
sa->dec_tf=NULL;
sa->sa_id=0;
}
priv->num_sa=0;
priv->tx_sa=-1;
free(priv);
}
arg->priv=NULL; /* return to fully uninitialised state */
return 0;
}
static size_t tf_choose_tx_sa( transop_tf_t * priv )
{
return priv->tx_sa; /* set in tick */
}
#define TRANSOP_TF_VER_SIZE 1 /* Support minor variants in encoding in one module. */
#define TRANSOP_TF_NONCE_SIZE 4
#define TRANSOP_TF_SA_SIZE 4
/** The twofish packet format consists of:
*
* - a 8-bit twofish encoding version in clear text
* - a 32-bit SA number in clear text
* - ciphertext encrypted from a 32-bit nonce followed by the payload.
*
* [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
* |<------ encrypted ------>|
*/
static int transop_encode_twofish( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
int len=-1;
transop_tf_t * priv = (transop_tf_t *)arg->priv;
uint8_t assembly[N2N_PKT_BUF_SIZE];
uint32_t * pnonce;
if ( (in_len + TRANSOP_TF_NONCE_SIZE) <= N2N_PKT_BUF_SIZE )
{
if ( (in_len + TRANSOP_TF_NONCE_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_VER_SIZE) <= out_len )
{
size_t idx=0;
sa_twofish_t * sa;
size_t tx_sa_num = 0;
/* The transmit sa is periodically updated */
tx_sa_num = tf_choose_tx_sa( priv );
sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
traceEvent( TRACE_DEBUG, "encode_twofish %lu with SA %lu.", in_len, sa->sa_id );
/* Encode the twofish format version. */
encode_uint8( outbuf, &idx, N2N_TWOFISH_TRANSFORM_VERSION );
/* Encode the security association (SA) number */
encode_uint32( outbuf, &idx, sa->sa_id );
/* The assembly buffer is a source for encrypting data. The nonce is
* written in first followed by the packet payload. The whole
* contents of assembly are encrypted. */
pnonce = (uint32_t *)assembly;
*pnonce = rand();
memcpy( assembly + TRANSOP_TF_NONCE_SIZE, inbuf, in_len );
/* Encrypt the assembly contents and write the ciphertext after the SA. */
len = TwoFishEncryptRaw( assembly, /* source */
outbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE,
in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */
sa->enc_tf);
if ( len > 0 )
{
len += TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE; /* size of data carried in UDP. */
}
else
{
traceEvent( TRACE_ERROR, "encode_twofish encryption failed." );
}
}
else
{
traceEvent( TRACE_ERROR, "encode_twofish outbuf too small." );
}
}
else
{
traceEvent( TRACE_ERROR, "encode_twofish inbuf too big to encrypt." );
}
return len;
}
/* Search through the array of SAs to find the one with the required ID.
*
* @return array index where found or -1 if not found
*/
static ssize_t twofish_find_sa( const transop_tf_t * priv, const n2n_sa_t req_id )
{
size_t i;
for (i=0; i < priv->num_sa; ++i)
{
const sa_twofish_t * sa=NULL;
sa = &(priv->sa[i]);
if (req_id == sa->sa_id)
{
return i;
}
}
return -1;
}
/** The twofish packet format consists of:
*
* - a 8-bit twofish encoding version in clear text
* - a 32-bit SA number in clear text
* - ciphertext encrypted from a 32-bit nonce followed by the payload.
*
* [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
* |<------ encrypted ------>|
*/
static int transop_decode_twofish( n2n_trans_op_t * arg,
uint8_t * outbuf,
size_t out_len,
const uint8_t * inbuf,
size_t in_len )
{
int len=0;
transop_tf_t * priv = (transop_tf_t *)arg->priv;
uint8_t assembly[N2N_PKT_BUF_SIZE];
if ( ( (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */
&& (in_len >= (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_NONCE_SIZE) ) /* Has at least version, SA and nonce */
)
{
n2n_sa_t sa_rx;
ssize_t sa_idx=-1;
size_t rem=in_len;
size_t idx=0;
uint8_t tf_enc_ver=0;
/* Get the encoding version to make sure it is supported */
decode_uint8( &tf_enc_ver, inbuf, &rem, &idx );
if ( N2N_TWOFISH_TRANSFORM_VERSION == tf_enc_ver )
{
/* Get the SA number and make sure we are decrypting with the right one. */
decode_uint32( &sa_rx, inbuf, &rem, &idx );
sa_idx = twofish_find_sa(priv, sa_rx);
if ( sa_idx >= 0 )
{
sa_twofish_t * sa = &(priv->sa[sa_idx]);
traceEvent( TRACE_DEBUG, "decode_twofish %lu with SA %lu.", in_len, sa_rx, sa->sa_id );
len = TwoFishDecryptRaw( (void *)(inbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE),
assembly, /* destination */
(in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)),
sa->dec_tf);
if ( len > 0 )
{
/* Step over 4-byte random nonce value */
len -= TRANSOP_TF_NONCE_SIZE; /* size of ethernet packet */
memcpy( outbuf,
assembly + TRANSOP_TF_NONCE_SIZE,
len );
}
else
{
traceEvent( TRACE_ERROR, "decode_twofish decryption failed." );
}
}
else
{
/* Wrong security association; drop the packet as it is undecodable. */
traceEvent( TRACE_ERROR, "decode_twofish SA number %lu not found.", sa_rx );
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
}
}
else
{
/* Wrong security association; drop the packet as it is undecodable. */
traceEvent( TRACE_ERROR, "decode_twofish unsupported twofish version %u.", tf_enc_ver );
/* REVISIT: should be able to load a new SA at this point to complete the decoding. */
}
}
else
{
traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len );
}
return len;
}
static int transop_addspec_twofish( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
{
int retval = 1;
ssize_t pstat=-1;
transop_tf_t * priv = (transop_tf_t *)arg->priv;
uint8_t keybuf[N2N_MAX_KEYSIZE];
if ( priv->num_sa < N2N_TWOFISH_NUM_SA )
{
const char * op = (const char *)cspec->opaque;
const char * sep = index( op, '_' );
if ( sep )
{
char tmp[256];
size_t s;
s = sep - op;
memcpy( tmp, cspec->opaque, s );
tmp[s]=0;
s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
priv->sa[priv->num_sa].spec = *cspec;
priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
if ( pstat > 0 )
{
priv->sa[priv->num_sa].enc_tf = TwoFishInit( keybuf, pstat);
priv->sa[priv->num_sa].dec_tf = TwoFishInit( keybuf, pstat);
traceEvent( TRACE_DEBUG, "transop_addspec_twofish sa_id=%u data=%s.\n",
priv->sa[priv->num_sa].sa_id, sep+1);
++(priv->num_sa);
retval = 0;
}
}
else
{
traceEvent( TRACE_ERROR, "transop_addspec_twofish : bad key data - missing '_'.\n");
}
}
else
{
traceEvent( TRACE_ERROR, "transop_addspec_twofish : full.\n");
}
return retval;
}
static n2n_tostat_t transop_tick_twofish( n2n_trans_op_t * arg, time_t now )
{
transop_tf_t * priv = (transop_tf_t *)arg->priv;
size_t i;
int found=0;
n2n_tostat_t r;
memset( &r, 0, sizeof(r) );
traceEvent( TRACE_DEBUG, "transop_tf tick num_sa=%u", priv->num_sa );
for ( i=0; i < priv->num_sa; ++i )
{
if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
{
time_t remaining = priv->sa[i].spec.valid_until - now;
traceEvent( TRACE_INFO, "transop_tf choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
priv->tx_sa=i;
found=1;
break;
}
else
{
traceEvent( TRACE_DEBUG, "transop_tf tick rejecting sa=%u %lu -> %lu",
priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
}
}
if ( 0==found)
{
traceEvent( TRACE_INFO, "transop_tf no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
}
else
{
r.can_tx = 1;
r.tx_spec.t = N2N_TRANSFORM_ID_TWOFISH;
r.tx_spec = priv->sa[priv->tx_sa].spec;
}
return r;
}
int transop_twofish_setup( n2n_trans_op_t * ttt,
n2n_sa_t sa_num,
uint8_t * encrypt_pwd,
uint32_t encrypt_pwd_len )
{
int retval = 1;
transop_tf_t * priv = NULL;
if ( ttt->priv )
{
transop_deinit_twofish( ttt );
}
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) );
if ( NULL != priv )
{
size_t i;
sa_twofish_t * sa=NULL;
/* install the private structure. */
ttt->priv = priv;
for(i=0; i<N2N_TWOFISH_NUM_SA; ++i)
{
sa = &(priv->sa[i]);
sa->sa_id=0;
memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
sa->enc_tf=NULL;
sa->dec_tf=NULL;
}
priv->num_sa=1; /* There is one SA in the array. */
priv->tx_sa=0;
sa = &(priv->sa[priv->tx_sa]);
sa->sa_id=sa_num;
sa->spec.valid_until = 0x7fffffff;
/* This is a preshared key setup. Both Tx and Rx are using the same security association. */
sa->enc_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
sa->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
if ( (sa->enc_tf) && (sa->dec_tf) )
{
ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
ttt->deinit = transop_deinit_twofish;
ttt->addspec = transop_addspec_twofish;
ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */
ttt->fwd = transop_encode_twofish;
ttt->rev = transop_decode_twofish;
retval = 0;
}
else
{
traceEvent( TRACE_ERROR, "TwoFishInit failed" );
}
}
else
{
memset( ttt, 0, sizeof(n2n_trans_op_t) );
traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" );
}
return retval;
}
int transop_twofish_init( n2n_trans_op_t * ttt )
{
int retval = 1;
transop_tf_t * priv = NULL;
if ( ttt->priv )
{
transop_deinit_twofish( ttt );
}
memset( ttt, 0, sizeof( n2n_trans_op_t ) );
priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) );
if ( NULL != priv )
{
size_t i;
sa_twofish_t * sa=NULL;
/* install the private structure. */
ttt->priv = priv;
priv->num_sa=0;
priv->tx_sa=0; /* We will use this sa index for encoding. */
ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
ttt->addspec = transop_addspec_twofish;
ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */
ttt->deinit = transop_deinit_twofish;
ttt->fwd = transop_encode_twofish;
ttt->rev = transop_decode_twofish;
for(i=0; i<N2N_TWOFISH_NUM_SA; ++i)
{
sa = &(priv->sa[i]);
sa->sa_id=0;
memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
sa->enc_tf=NULL;
sa->dec_tf=NULL;
}
retval = 0;
}
else
{
memset( ttt, 0, sizeof(n2n_trans_op_t) );
traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" );
}
return retval;
}

132
tuntap_freebsd.c Normal file
View File

@ -0,0 +1,132 @@
/*
* (C) 2007-09 - Luca Deri <deri@ntop.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 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 see <http://www.gnu.org/licenses/>
*/
#include "n2n.h"
#ifdef __FreeBSD__
void tun_close(tuntap_dev *device);
/* ********************************** */
#define N2N_FREEBSD_TAPDEVICE_SIZE 32
int tuntap_open(tuntap_dev *device /* ignored */,
char *dev,
const char *address_mode, /* static or dhcp */
char *device_ip,
char *device_mask,
const char * device_mac,
int mtu) {
int i;
char tap_device[N2N_FREEBSD_TAPDEVICE_SIZE];
for (i = 0; i < 255; i++) {
snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i);
device->fd = open(tap_device, O_RDWR);
if(device->fd > 0) {
traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device);
break;
}
}
if(device->fd < 0) {
traceEvent(TRACE_ERROR, "Unable to open tap device");
return(-1);
} else {
char buf[256];
FILE *fd;
device->ip_addr = inet_addr(device_ip);
if ( device_mac && device_mac[0] != '\0' )
{
/* FIXME - This is not tested. Might be wrong syntax for OS X */
/* Set the hw address before bringing the if up. */
snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s",
i, device_mac);
system(buf);
}
snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up",
i, device_ip, device_mask, mtu);
system(buf);
traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)",
i, device_ip, device_mask);
/* Read MAC address */
snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i);
/* traceEvent(TRACE_INFO, "%s", buf); */
fd = popen(buf, "r");
if(fd < 0) {
tun_close(device);
return(-1);
} else {
int a, b, c, d, e, f;
buf[0] = 0;
fgets(buf, sizeof(buf), fd);
pclose(fd);
if(buf[0] == '\0') {
traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address");
exit(0);
}
traceEvent(TRACE_NORMAL, "Interface tap%d mac %s", i, buf);
if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) {
device->mac_addr[0] = a, device->mac_addr[1] = b;
device->mac_addr[2] = c, device->mac_addr[3] = d;
device->mac_addr[4] = e, device->mac_addr[5] = f;
}
}
}
/* read_mac(dev, device->mac_addr); */
return(device->fd);
}
/* ********************************** */
int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
return(read(tuntap->fd, buf, len));
}
/* ********************************** */
int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
return(write(tuntap->fd, buf, len));
}
/* ********************************** */
void tuntap_close(struct tuntap_dev *tuntap) {
close(tuntap->fd);
}
/* Fill out the ip_addr value from the interface. Called to pick up dynamic
* address changes. */
void tuntap_get_address(struct tuntap_dev *tuntap)
{
}
#endif /* #ifdef __FreeBSD__ */

165
tuntap_linux.c Normal file
View File

@ -0,0 +1,165 @@
/*
* (C) 2007-09 - Luca Deri <deri@ntop.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 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 "n2n.h"
#ifdef __linux__
static void read_mac(char *ifname, n2n_mac_t mac_addr) {
int _sock, res;
struct ifreq ifr;
macstr_t mac_addr_buf;
memset (&ifr,0,sizeof(struct ifreq));
/* Dummy socket, just to make ioctls with */
_sock=socket(PF_INET, SOCK_DGRAM, 0);
strcpy(ifr.ifr_name, ifname);
res = ioctl(_sock,SIOCGIFHWADDR,&ifr);
if (res<0) {
perror ("Get hw addr");
} else
memcpy(mac_addr, ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);
traceEvent(TRACE_NORMAL, "Interface %s has MAC %s",
ifname,
macaddr_str(mac_addr_buf, mac_addr ));
close(_sock);
}
/* ********************************** */
/** @brief Open and configure the TAP device for packet read/write.
*
* This routine creates the interface via the tuntap driver then uses ifconfig
* to configure address/mask and MTU.
*
* @param device - [inout] a device info holder object
* @param dev - user-defined name for the new iface,
* if NULL system will assign a name
* @param device_ip - address of iface
* @param device_mask - netmask for device_ip
* @param mtu - MTU for device_ip
*
* @return - negative value on error
* - non-negative file-descriptor on success
*/
int tuntap_open(tuntap_dev *device,
char *dev, /* user-definable interface name, eg. edge0 */
const char *address_mode, /* static or dhcp */
char *device_ip,
char *device_mask,
const char * device_mac,
int mtu) {
char *tuntap_device = "/dev/net/tun";
#define N2N_LINUX_SYSTEMCMD_SIZE 128
char buf[N2N_LINUX_SYSTEMCMD_SIZE];
struct ifreq ifr;
int rc;
device->fd = open(tuntap_device, O_RDWR);
if(device->fd < 0) {
printf("ERROR: ioctl() [%s][%d]\n", strerror(errno), errno);
return -1;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP|IFF_NO_PI; /* Want a TAP device for layer 2 frames. */
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
rc = ioctl(device->fd, TUNSETIFF, (void *)&ifr);
if(rc < 0) {
traceEvent(TRACE_ERROR, "ioctl() [%s][%d]\n", strerror(errno), rc);
close(device->fd);
return -1;
}
/* Store the device name for later reuse */
strncpy(device->dev_name, ifr.ifr_name, MIN(IFNAMSIZ, N2N_IFNAMSIZ) );
if ( device_mac && device_mac[0] != '\0' )
{
/* Set the hw address before bringing the if up. */
snprintf(buf, sizeof(buf), "/sbin/ifconfig %s hw ether %s",
ifr.ifr_name, device_mac );
system(buf);
traceEvent(TRACE_INFO, "Setting MAC: %s", buf);
}
if ( 0 == strncmp( "dhcp", address_mode, 5 ) )
{
snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s mtu %d up",
ifr.ifr_name, device_ip, mtu);
}
else
{
snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s netmask %s mtu %d up",
ifr.ifr_name, device_ip, device_mask, mtu);
}
system(buf);
traceEvent(TRACE_INFO, "Bringing up: %s", buf);
device->ip_addr = inet_addr(device_ip);
device->device_mask = inet_addr(device_mask);
read_mac(dev, device->mac_addr);
return(device->fd);
}
int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
return(read(tuntap->fd, buf, len));
}
int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
return(write(tuntap->fd, buf, len));
}
void tuntap_close(struct tuntap_dev *tuntap) {
close(tuntap->fd);
}
/* Fill out the ip_addr value from the interface. Called to pick up dynamic
* address changes. */
void tuntap_get_address(struct tuntap_dev *tuntap)
{
FILE * fp=NULL;
ssize_t nread=0;
char buf[N2N_LINUX_SYSTEMCMD_SIZE];
/* Would rather have a more direct way to get the inet address but a netlink
* socket is overkill and probably less portable than ifconfig and sed. */
/* If the interface has no address (0.0.0.0) there will be no inet addr
* line and the returned string will be empty. */
snprintf( buf, sizeof(buf), "/sbin/ifconfig %s | /bin/sed -e '/inet addr:/!d' -e 's/^.*inet addr://' -e 's/ .*$//'",
tuntap->dev_name );
fp=popen(buf, "r");
if (fp )
{
memset(buf,0,N2N_LINUX_SYSTEMCMD_SIZE); /* make sure buf is NULL terminated. */
nread=fread(buf, 1, 15, fp);
fclose(fp);
fp=NULL;
traceEvent(TRACE_INFO, "ifconfig address = %s", buf);
tuntap->ip_addr = inet_addr(buf);
}
}
#endif /* #ifdef __linux__ */

146
tuntap_netbsd.c Normal file
View File

@ -0,0 +1,146 @@
/*
* (C) 2007-09 - Luca Deri <deri@ntop.org>
* (C) 2009 - Alaric Snell-Pym <alaric@kitten-technologies.co.uk>
*
* 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 see <http://www.gnu.org/licenses/>
*/
#include "n2n.h"
#ifdef __NetBSD__
#include <errno.h>
#include <string.h>
#include <net/if_tap.h>
void tun_close(tuntap_dev *device);
/* ********************************** */
#define N2N_NETBSD_TAPDEVICE_SIZE 32
int tuntap_open(tuntap_dev *device /* ignored */,
char *dev,
const char *address_mode, /* static or dhcp */
char *device_ip,
char *device_mask,
const char * device_mac,
int mtu) {
char tap_device[N2N_NETBSD_TAPDEVICE_SIZE];
struct ifreq req;
if (dev) {
snprintf(tap_device, sizeof(tap_device), "/dev/%s", dev);
device->fd = open(tap_device, O_RDWR);
snprintf(tap_device, sizeof(tap_device), "%s", dev);
}
else {
device->fd = open("/dev/tap", O_RDWR);
if(device->fd >= 0) {
if (ioctl(device->fd, TAPGIFNAME, &req) == -1) {
traceEvent(TRACE_ERROR, "Unable to obtain name of tap device (%s)", strerror(errno));
close(device->fd);
return(-1);
}
else {
snprintf(tap_device, sizeof(tap_device), req.ifr_name);
}
}
}
if(device->fd < 0) {
traceEvent(TRACE_ERROR, "Unable to open tap device (%s)", strerror(errno));
return(-1);
} else {
char buf[256];
FILE *fd;
traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device);
device->ip_addr = inet_addr(device_ip);
if ( device_mac && device_mac[0] != '\0' )
{
/* Set the hw address before bringing the if up. */
snprintf(buf, sizeof(buf), "ifconfig %s link %s active",
tap_device, device_mac);
system(buf);
}
snprintf(buf, sizeof(buf), "ifconfig %s %s netmask %s mtu %d up",
tap_device, device_ip, device_mask, mtu);
system(buf);
traceEvent(TRACE_NORMAL, "Interface %s up and running (%s/%s)",
tap_device, device_ip, device_mask);
/* Read MAC address */
snprintf(buf, sizeof(buf), "ifconfig %s |grep address|cut -c 11-28", tap_device);
/* traceEvent(TRACE_INFO, "%s", buf); */
fd = popen(buf, "r");
if(fd < 0) {
tun_close(device);
return(-1);
} else {
int a, b, c, d, e, f;
buf[0] = 0;
fgets(buf, sizeof(buf), fd);
pclose(fd);
if(buf[0] == '\0') {
traceEvent(TRACE_ERROR, "Unable to read %s interface MAC address", tap_device);
exit(0);
}
traceEvent(TRACE_NORMAL, "Interface %s mac %s", tap_device, buf);
if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) {
device->mac_addr[0] = a, device->mac_addr[1] = b;
device->mac_addr[2] = c, device->mac_addr[3] = d;
device->mac_addr[4] = e, device->mac_addr[5] = f;
}
}
}
/* read_mac(dev, device->mac_addr); */
return(device->fd);
}
/* ********************************** */
int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
return(read(tuntap->fd, buf, len));
}
/* ********************************** */
int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
return(write(tuntap->fd, buf, len));
}
/* ********************************** */
void tuntap_close(struct tuntap_dev *tuntap) {
close(tuntap->fd);
}
/* Fill out the ip_addr value from the interface. Called to pick up dynamic
* address changes. */
void tuntap_get_address(struct tuntap_dev *tuntap)
{
}
#endif /* #ifdef __NetBSD__ */

132
tuntap_osx.c Normal file
View File

@ -0,0 +1,132 @@
/*
* (C) 2007-09 - Luca Deri <deri@ntop.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 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 see <http://www.gnu.org/licenses/>
*/
#include "n2n.h"
#ifdef _DARWIN_
void tun_close(tuntap_dev *device);
/* ********************************** */
#define N2N_OSX_TAPDEVICE_SIZE 32
int tuntap_open(tuntap_dev *device /* ignored */,
char *dev,
const char *address_mode, /* static or dhcp */
char *device_ip,
char *device_mask,
const char * device_mac,
int mtu) {
int i;
char tap_device[N2N_OSX_TAPDEVICE_SIZE];
for (i = 0; i < 255; i++) {
snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i);
device->fd = open(tap_device, O_RDWR);
if(device->fd > 0) {
traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device);
break;
}
}
if(device->fd < 0) {
traceEvent(TRACE_ERROR, "Unable to open tap device");
return(-1);
} else {
char buf[256];
FILE *fd;
device->ip_addr = inet_addr(device_ip);
if ( device_mac && device_mac[0] != '\0' )
{
/* FIXME - This is not tested. Might be wrong syntax for OS X */
/* Set the hw address before bringing the if up. */
snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s",
i, device_mac);
system(buf);
}
snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up",
i, device_ip, device_mask, mtu);
system(buf);
traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)",
i, device_ip, device_mask);
/* Read MAC address */
snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i);
/* traceEvent(TRACE_INFO, "%s", buf); */
fd = popen(buf, "r");
if(fd < 0) {
tun_close(device);
return(-1);
} else {
int a, b, c, d, e, f;
buf[0] = 0;
fgets(buf, sizeof(buf), fd);
pclose(fd);
if(buf[0] == '\0') {
traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address");
exit(0);
}
traceEvent(TRACE_NORMAL, "Interface tap%d [MTU %d] mac %s", i, mtu, buf);
if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) {
device->mac_addr[0] = a, device->mac_addr[1] = b;
device->mac_addr[2] = c, device->mac_addr[3] = d;
device->mac_addr[4] = e, device->mac_addr[5] = f;
}
}
}
/* read_mac(dev, device->mac_addr); */
return(device->fd);
}
/* ********************************** */
int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
return(read(tuntap->fd, buf, len));
}
/* ********************************** */
int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
return(write(tuntap->fd, buf, len));
}
/* ********************************** */
void tuntap_close(struct tuntap_dev *tuntap) {
close(tuntap->fd);
}
/* Fill out the ip_addr value from the interface. Called to pick up dynamic
* address changes. */
void tuntap_get_address(struct tuntap_dev *tuntap)
{
}
#endif /* _DARWIN_ */

1031
twofish.c Normal file

File diff suppressed because it is too large Load Diff

292
twofish.h Normal file
View File

@ -0,0 +1,292 @@
/* $Id: twofish.h,v 2.0 2002/08/11 22:32:25 fknobbe Exp $
*
*
* Copyright (C) 1997-2000 The Cryptix Foundation Limited.
* Copyright (C) 2000 Farm9.
* Copyright (C) 2001 Frank Knobbe.
* All rights reserved.
*
* For Cryptix code:
* Use, modification, copying and distribution of this software is subject
* the terms and conditions of the Cryptix General Licence. You should have
* received a copy of the Cryptix General Licence along with this library;
* if not, you can download a copy from http://www.cryptix.org/ .
*
* For Farm9:
* --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and
* ciphertext stealing technique, added AsciiTwofish class for easy encryption
* decryption of text strings
*
* Frank Knobbe <frank@knobbe.us>:
* --- April 2001, converted from C++ to C, prefixed global variables
* with TwoFish, substituted some defines, changed functions to make use of
* variables supplied in a struct, modified and added routines for modular calls.
* Cleaned up the code so that defines are used instead of fixed 16's and 32's.
* Created two general purpose crypt routines for one block and multiple block
* encryption using Joh's CBC code.
* Added crypt routines that use a header (with a magic and data length).
* (Basically a major rewrite).
*
* Note: Routines labeled _TwoFish are private and should not be used
* (or with extreme caution).
*
*/
#ifndef __TWOFISH_LIBRARY_HEADER__
#define __TWOFISH_LIBRARY_HEADER__
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE !FALSE
#endif
#ifndef bool
#define bool int
#endif
#ifdef WIN32
#include "win32/n2n_win32.h"
#endif
#ifndef _MSC_VER
/* Not shipped with Visual Studio (as stated by the stdint.h wikipedia page) */
#include <stdint.h> /* defines uintN_t types */
#endif
#ifdef __sun__ /* Should be HAVE_SYS_TYPES */
/* The following are redefinitions if sys/types.h has been included too.*/
typedef uint32_t uint32_t;
typedef uint8_t uint8_t;
#endif /* #ifdef __sun__ */
/* Constants */
#define TwoFish_DEFAULT_PW "SnortHas2FishEncryptionRoutines!" /* default password (not more than 32 chars) */
#define TwoFish_DEFAULT_PW_LEN 32
#define TwoFish_MAGIC "TwoFish" /* to indentify a successful decryption */
enum
{ TwoFish_KEY_SIZE = 256, /* Valid values: 64, 128, 192, 256 */
/* User 256, other key sizes have not been tested. */
/* (But should work. I substitutes as much as */
/* I could with this define.) */
TwoFish_ROUNDS = 16,
TwoFish_BLOCK_SIZE = 16, /* bytes in a data-block */
TwoFish_KEY_LENGTH = TwoFish_KEY_SIZE/8, /* 32= 256-bit key */
TwoFish_TOTAL_SUBKEYS = 4+4+2*TwoFish_ROUNDS,
TwoFish_MAGIC_LEN = TwoFish_BLOCK_SIZE-8,
TwoFish_SK_BUMP = 0x01010101,
TwoFish_SK_ROTL = 9,
TwoFish_P_00 = 1,
TwoFish_P_01 = 0,
TwoFish_P_02 = 0,
TwoFish_P_03 = TwoFish_P_01 ^ 1,
TwoFish_P_04 = 1,
TwoFish_P_10 = 0,
TwoFish_P_11 = 0,
TwoFish_P_12 = 1,
TwoFish_P_13 = TwoFish_P_11 ^ 1,
TwoFish_P_14 = 0,
TwoFish_P_20 = 1,
TwoFish_P_21 = 1,
TwoFish_P_22 = 0,
TwoFish_P_23 = TwoFish_P_21 ^ 1,
TwoFish_P_24 = 0,
TwoFish_P_30 = 0,
TwoFish_P_31 = 1,
TwoFish_P_32 = 1,
TwoFish_P_33 = TwoFish_P_31 ^ 1,
TwoFish_P_34 = 1,
TwoFish_GF256_FDBK = 0x169,
TwoFish_GF256_FDBK_2 = 0x169 / 2,
TwoFish_GF256_FDBK_4 = 0x169 / 4,
TwoFish_RS_GF_FDBK = 0x14D, /* field generator */
TwoFish_MDS_GF_FDBK = 0x169 /* primitive polynomial for GF(256) */
};
/* Global data structure for callers */
typedef struct
{
uint32_t sBox[4 * 256]; /* Key dependent S-box */
uint32_t subKeys[TwoFish_TOTAL_SUBKEYS]; /* Subkeys */
uint8_t key[TwoFish_KEY_LENGTH]; /* Encryption Key */
uint8_t *output; /* Pointer to output buffer */
uint8_t qBlockPlain[TwoFish_BLOCK_SIZE]; /* Used by CBC */
uint8_t qBlockCrypt[TwoFish_BLOCK_SIZE];
uint8_t prevCipher[TwoFish_BLOCK_SIZE];
struct /* Header for crypt functions. Has to be at least one block long. */
{ uint32_t salt; /* Random salt in first block (will salt the rest through CBC) */
uint8_t length[4]; /* The amount of data following the header */
uint8_t magic[TwoFish_MAGIC_LEN]; /* Magic to identify successful decryption */
} header;
bool qBlockDefined;
bool dontflush;
} TWOFISH;
#ifndef __TWOFISH_LIBRARY_SOURCE__
extern bool TwoFish_srand; /* if set to TRUE (default), first call of TwoFishInit will seed rand(); */
/* call of TwoFishInit */
#endif
/**** Public Functions ****/
/* TwoFish Initialization
*
* This routine generates a global data structure for use with TwoFish,
* initializes important values (such as subkeys, sBoxes), generates subkeys
* and precomputes the MDS matrix if not already done.
*
* Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!')
*
* Output: Pointer to TWOFISH structure. This data structure contains key dependent data.
* This pointer is used with all other crypt functions.
*/
TWOFISH *TwoFishInit(const uint8_t *userkey, uint32_t keysize );
/* TwoFish Destroy
*
* Nothing else but a free...
*
* Input: Pointer to the TwoFish structure.
*
*/
void TwoFishDestroy(TWOFISH *tfdata);
/* TwoFish Alloc
*
* Allocates enough memory for the output buffer as required.
*
* Input: Length of the plaintext.
* Boolean flag for BinHex Output.
* Pointer to the TwoFish structure.
*
* Output: Returns a pointer to the memory allocated.
*/
void *TwoFishAlloc(uint32_t len,bool binhex,bool decrypt,TWOFISH *tfdata);
/* TwoFish Free
*
* Free's the allocated buffer.
*
* Input: Pointer to the TwoFish structure
*
* Output: (none)
*/
void TwoFishFree(TWOFISH *tfdata);
/* TwoFish Set Output
*
* If you want to allocate the output buffer yourself,
* then you can set it with this function.
*
* Input: Pointer to your output buffer
* Pointer to the TwoFish structure
*
* Output: (none)
*/
void TwoFishSetOutput(uint8_t *outp,TWOFISH *tfdata);
/* TwoFish Raw Encryption
*
* Does not use header, but does use CBC (if more than one block has to be encrypted).
*
* Input: Pointer to the buffer of the plaintext to be encrypted.
* Pointer to the buffer receiving the ciphertext.
* The length of the plaintext buffer.
* The TwoFish structure.
*
* Output: The amount of bytes encrypted if successful, otherwise 0.
*/
uint32_t TwoFishEncryptRaw(uint8_t *in,uint8_t *out,uint32_t len,TWOFISH *tfdata);
/* TwoFish Raw Decryption
*
* Does not use header, but does use CBC (if more than one block has to be decrypted).
*
* Input: Pointer to the buffer of the ciphertext to be decrypted.
* Pointer to the buffer receiving the plaintext.
* The length of the ciphertext buffer (at least one cipher block).
* The TwoFish structure.
*
* Output: The amount of bytes decrypted if successful, otherwise 0.
*/
uint32_t TwoFishDecryptRaw(uint8_t *in,uint8_t *out,uint32_t len,TWOFISH *tfdata);
/* TwoFish Encryption
*
* Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
* this routine will alloc the memory. In addition, it will include a small 'header'
* containing the magic and some salt. That way the decrypt routine can check if the
* packet got decrypted successfully, and return 0 instead of garbage.
*
* Input: Pointer to the buffer of the plaintext to be encrypted.
* Pointer to the pointer to the buffer receiving the ciphertext.
* The pointer either points to user allocated output buffer space, or to NULL, in which case
* this routine will set the pointer to the buffer allocated through the struct.
* The length of the plaintext buffer.
* Can be -1 if the input is a null terminated string, in which case we'll count for you.
* Boolean flag for BinHex Output (if used, output will be twice as large as input).
* Note: BinHex conversion overwrites (converts) input buffer!
* The TwoFish structure.
*
* Output: The amount of bytes encrypted if successful, otherwise 0.
*/
uint32_t TwoFishEncrypt(uint8_t *in,uint8_t **out,signed long len,bool binhex,TWOFISH *tfdata);
/* TwoFish Decryption
*
* Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
* this routine will alloc the memory. In addition, it will check the small 'header'
* containing the magic. If magic does not match we return 0. Otherwise we return the
* amount of bytes decrypted (should be the same as the length in the header).
*
* Input: Pointer to the buffer of the ciphertext to be decrypted.
* Pointer to the pointer to the buffer receiving the plaintext.
* The pointer either points to user allocated output buffer space, or to NULL, in which case
* this routine will set the pointer to the buffer allocated through the struct.
* The length of the ciphertext buffer.
* Can be -1 if the input is a null terminated binhex string, in which case we'll count for you.
* Boolean flag for BinHex Input (if used, plaintext will be half as large as input).
* Note: BinHex conversion overwrites (converts) input buffer!
* The TwoFish structure.
*
* Output: The amount of bytes decrypted if successful, otherwise 0.
*/
uint32_t TwoFishDecrypt(uint8_t *in,uint8_t **out,signed long len,bool binhex,TWOFISH *tfdata);
/**** Private Functions ****/
uint8_t TwoFish__b(uint32_t x,int n);
void _TwoFish_BinHex(uint8_t *buf,uint32_t len,bool bintohex);
uint32_t _TwoFish_CryptRawCBC(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata);
uint32_t _TwoFish_CryptRaw16(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata);
uint32_t _TwoFish_CryptRaw(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata);
void _TwoFish_PrecomputeMDSmatrix(void);
void _TwoFish_MakeSubKeys(TWOFISH *tfdata);
void _TwoFish_qBlockPush(uint8_t *p,uint8_t *c,TWOFISH *tfdata);
void _TwoFish_qBlockPop(uint8_t *p,uint8_t *c,TWOFISH *tfdata);
void _TwoFish_ResetCBC(TWOFISH *tfdata);
void _TwoFish_FlushOutput(uint8_t *b,uint32_t len,TWOFISH *tfdata);
void _TwoFish_BlockCrypt(uint8_t *in,uint8_t *out,uint32_t size,int decrypt,TWOFISH *tfdata);
void _TwoFish_BlockCrypt16(uint8_t *in,uint8_t *out,bool decrypt,TWOFISH *tfdata);
uint32_t _TwoFish_RS_MDS_Encode(uint32_t k0,uint32_t k1);
uint32_t _TwoFish_F32(uint32_t k64Cnt,uint32_t x,uint32_t *k32);
uint32_t _TwoFish_Fe320(uint32_t *lsBox,uint32_t x);
uint32_t _TwoFish_Fe323(uint32_t *lsBox,uint32_t x);
uint32_t _TwoFish_Fe32(uint32_t *lsBox,uint32_t x,uint32_t R);
#endif

3
version.c Normal file
View File

@ -0,0 +1,3 @@
const char * n2n_sw_version = N2N_VERSION;
const char * n2n_sw_osName = N2N_OSNAME;
const char * n2n_sw_buildDate = __DATE__ " " __TIME__;

4
win32/CMakeLists.txt Normal file
View File

@ -0,0 +1,4 @@
add_library(n2n_win32
win32/getopt1.c
win32/getopt.c
win32/wintap.c)

26
win32/DotNet/n2n.sln Normal file
View File

@ -0,0 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "edge", "n2n.vcproj", "{4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "supernode", "supernode.vcproj", "{BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Debug|Win32.ActiveCfg = Debug|Win32
{4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Debug|Win32.Build.0 = Debug|Win32
{4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Release|Win32.ActiveCfg = Release|Win32
{4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}.Release|Win32.Build.0 = Release|Win32
{BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Debug|Win32.ActiveCfg = Debug|Win32
{BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Debug|Win32.Build.0 = Debug|Win32
{BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Release|Win32.ActiveCfg = Release|Win32
{BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

BIN
win32/DotNet/n2n.suo Normal file

Binary file not shown.

300
win32/DotNet/n2n.vcproj Normal file
View File

@ -0,0 +1,300 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="edge"
ProjectGUID="{4911ADD4-08A3-4C9F-B9C9-9492DA10D01D}"
RootNamespace="n2n"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
UseUnicodeResponseFiles="false"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib Advapi32.lib libeay32.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib Advapi32.lib libeay32.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\..\edge.c"
>
</File>
<File
RelativePath="..\getopt.c"
>
</File>
<File
RelativePath="..\getopt1.c"
>
</File>
<File
RelativePath="..\..\minilzo.c"
>
</File>
<File
RelativePath="..\..\n2n.c"
>
</File>
<File
RelativePath="..\..\n2n_keyfile.c"
>
</File>
<File
RelativePath="..\..\transform_aes.c"
>
</File>
<File
RelativePath="..\..\transform_null.c"
>
</File>
<File
RelativePath="..\..\transform_tf.c"
>
</File>
<File
RelativePath="..\..\twofish.c"
>
</File>
<File
RelativePath="..\version-msvc.c"
>
</File>
<File
RelativePath="..\wintap.c"
>
</File>
<File
RelativePath="..\..\wire.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\getopt.h"
>
</File>
<File
RelativePath="..\..\lzoconf.h"
>
</File>
<File
RelativePath="..\..\lzodefs.h"
>
</File>
<File
RelativePath="..\..\minilzo.h"
>
</File>
<File
RelativePath="..\..\n2n.h"
>
</File>
<File
RelativePath="..\..\n2n_keyfile.h"
>
</File>
<File
RelativePath="..\..\n2n_transforms.h"
>
</File>
<File
RelativePath="..\n2n_win32.h"
>
</File>
<File
RelativePath="..\..\n2n_wire.h"
>
</File>
<File
RelativePath="..\..\twofish.h"
>
</File>
<File
RelativePath="..\wintap.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
<File
RelativePath="..\..\HACKING"
>
</File>
<File
RelativePath="..\..\README"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,226 @@
<?xml version="1.0" encoding="windows-1250"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="supernode"
ProjectGUID="{BDB93CAB-BE22-4ED6-9A05-2E4D6F1D76E1}"
RootNamespace="supernode"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
GenerateDebugInformation="true"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="false"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
EnableFunctionLevelLinking="false"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib"
GenerateDebugInformation="true"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\getopt.c"
>
</File>
<File
RelativePath="..\getopt1.c"
>
</File>
<File
RelativePath="..\..\n2n.c"
>
</File>
<File
RelativePath="..\..\sn.c"
>
</File>
<File
RelativePath="..\version-msvc.c"
>
</File>
<File
RelativePath="..\wintap.c"
>
</File>
<File
RelativePath="..\..\wire.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\getopt.h"
>
</File>
<File
RelativePath="..\..\n2n.h"
>
</File>
<File
RelativePath="..\n2n_win32.h"
>
</File>
<File
RelativePath="..\..\n2n_wire.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

1074
win32/getopt.c Normal file

File diff suppressed because it is too large Load Diff

169
win32/getopt.h Normal file
View File

@ -0,0 +1,169 @@
/* Declarations for getopt.
Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef _GETOPT_H
#ifndef __need_getopt
# define _GETOPT_H 1
#endif
#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;
#ifndef __need_getopt
/* 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
#endif /* need getopt */
/* Get definitions and prototypes for functions to process the
arguments in ARGV (ARGC of them, minus the program name) for
options given in OPTS.
Return the option character from OPTS just read. Return -1 when
there are no more options. For unrecognized options, or options
missing arguments, `optopt' is set to the option letter, and '?' is
returned.
The OPTS string is a list of characters which are recognized option
letters, optionally followed by colons, specifying that that letter
takes an argument, to be placed in `optarg'.
If a letter in OPTS is followed by two colons, its argument is
optional. This behavior is specific to the GNU `getopt'.
The argument `--' causes premature termination of argument
scanning, explicitly telling `getopt' that there are no more
options.
If OPTS begins with `--', then non-option arguments are treated as
arguments to the option '\0'. This behavior is specific to the GNU
`getopt'. */
#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__ */
# ifndef __need_getopt
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);
# endif
#else /* not __STDC__ */
extern int getopt ();
# ifndef __need_getopt
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
# endif
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
/* Make sure we later can get all the definitions and declarations. */
#undef __need_getopt
#endif /* getopt.h */

188
win32/getopt1.c Normal file
View File

@ -0,0 +1,188 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, 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 */

109
win32/n2n_win32.h Normal file
View File

@ -0,0 +1,109 @@
/*
(C) 2007-09 - Luca Deri <deri@ntop.org>
*/
#ifndef _N2N_WIN32_H_
#define _N2N_WIN32_H_
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#if defined(__MINGW32__)
/* should be defined here and before winsock gets included */
#define _WIN32_WINNT 0x501 //Otherwise the linker doesnt find getaddrinfo
#include <inttypes.h>
#endif /* #if defined(__MINGW32__) */
#include <winsock2.h>
#include <windows.h>
#include <winioctl.h>
#include "wintap.h"
#ifdef _MSC_VER
#include "getopt.h"
/* Other Win environments are expected to support stdint.h */
/* stdint.h typedefs (C99) (not present in Visual Studio) */
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef unsigned char uint8_t;
/* sys/types.h typedefs (not present in Visual Studio) */
typedef unsigned int u_int32_t;
typedef unsigned short u_int16_t;
typedef unsigned char u_int8_t;
typedef int ssize_t;
#endif /* #ifdef _MSC_VER */
typedef unsigned long in_addr_t;
#define EAFNOSUPPORT WSAEAFNOSUPPORT
#define MAX(a,b) (a > b ? a : b)
#define MIN(a,b) (a < b ? a : b)
#define snprintf _snprintf
#define strdup _strdup
#define socklen_t int
#define ETH_ADDR_LEN 6
/*
* Structure of a 10Mb/s Ethernet header.
*/
struct ether_hdr
{
uint8_t dhost[ETH_ADDR_LEN];
uint8_t shost[ETH_ADDR_LEN];
uint16_t type; /* higher layer protocol encapsulated */
};
typedef struct ether_hdr ether_hdr_t;
/* ************************************* */
struct ip {
#if BYTE_ORDER == LITTLE_ENDIAN
u_char ip_hl:4, /* header length */
ip_v:4; /* version */
#else
u_char ip_v:4, /* version */
ip_hl:4; /* header length */
#endif
u_char ip_tos; /* type of service */
short ip_len; /* total length */
u_short ip_id; /* identification */
short ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
/* ************************************* */
typedef struct tuntap_dev {
HANDLE device_handle;
char *device_name;
char *ifName;
OVERLAPPED overlap_read, overlap_write;
uint8_t mac_addr[6];
uint32_t ip_addr, device_mask;
unsigned int mtu;
} tuntap_dev;
#define index(a, b) strchr(a, b)
#endif

3
win32/version-msvc.c Normal file
View File

@ -0,0 +1,3 @@
const char * n2n_sw_version = "2.0.0";
const char * n2n_sw_osName = "Win32";
const char * n2n_sw_buildDate = __DATE__ " " __TIME__;

310
win32/wintap.c Normal file
View File

@ -0,0 +1,310 @@
/*
(C) 2007-09 - Luca Deri <deri@ntop.org>
*/
#include "../n2n.h"
#include "n2n_win32.h"
/* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
#define MTU 1518
void initWin32() {
WSADATA wsaData;
int err;
err = WSAStartup(MAKEWORD(2, 2), &wsaData );
if( err != 0 ) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("FATAL ERROR: unable to initialise Winsock 2.x.");
exit(-1);
}
}
int open_wintap(struct tuntap_dev *device,
const char * address_mode, /* "static" or "dhcp" */
char *device_ip,
char *device_mask,
const char *device_mac,
int mtu) {
HKEY key, key2;
LONG rc;
char regpath[1024], cmd[256];
char adapterid[1024];
char adaptername[1024];
char tapname[1024];
long len;
int found = 0;
int err, i;
ULONG status = TRUE;
memset(device, 0, sizeof(struct tuntap_dev));
device->device_handle = INVALID_HANDLE_VALUE;
device->device_name = NULL;
device->ifName = NULL;
device->ip_addr = inet_addr(device_ip);
/* Open registry and look for network adapters */
if((rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key))) {
printf("Unable to read registry: [rc=%d]\n", rc);
exit(-1);
/* MSVC Note: If you keep getting rc=2 errors, make sure you set:
Project -> Properties -> Configuration Properties -> General -> Character set
to: "Use Multi-Byte Character Set"
*/
}
for (i = 0; ; i++) {
len = sizeof(adapterid);
if(RegEnumKeyEx(key, i, (LPTSTR)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, (LPCSTR)regpath, 0, KEY_READ, &key2))
continue;
len = sizeof(adaptername);
err = RegQueryValueEx(key2, "Name", 0, 0, adaptername, &len);
RegCloseKey(key2);
if(err)
continue;
if(device->device_name) {
if(!strcmp(device->device_name, adapterid)) {
found = 1;
break;
} else
continue;
}
if(device->ifName) {
if(!strcmp(device->ifName, adaptername)) {
found = 1;
break;
} else
continue;
}
_snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid);
device->device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ,
0, /* Don't let other processes share or open
the resource until the handle's been closed */
0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
if(device->device_handle != INVALID_HANDLE_VALUE) {
found = 1;
break;
}
}
RegCloseKey(key);
if(!found) {
printf("No Windows tap device found!\n");
exit(0);
}
/* ************************************** */
if(!device->device_name)
device->device_name = _strdup(adapterid);
if(!device->ifName)
device->ifName = _strdup(adaptername);
/* Try to open the corresponding tap device->device_name */
if(device->device_handle == INVALID_HANDLE_VALUE) {
_snprintf(tapname, sizeof(tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device->device_name);
device->device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0,
OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
}
if(device->device_handle == INVALID_HANDLE_VALUE) {
printf("%s (%s) is not a usable Windows tap device\n", device->device_name, device->ifName);
exit(-1);
}
/* Get MAC address from tap device->device_name */
if(!DeviceIoControl(device->device_handle, TAP_IOCTL_GET_MAC,
device->mac_addr, sizeof(device->mac_addr),
device->mac_addr, sizeof(device->mac_addr), &len, 0)) {
printf("Could not get MAC address from Windows tap %s (%s)\n",
device->device_name, device->ifName);
return -1;
}
device->mtu = mtu;
printf("Open device [name=%s][ip=%s][ifName=%s][MTU=%d][mac=%02X:%02X:%02X:%02X:%02X:%02X]\n",
device->device_name, device_ip, device->ifName, device->mtu,
device->mac_addr[0] & 0xFF,
device->mac_addr[1] & 0xFF,
device->mac_addr[2] & 0xFF,
device->mac_addr[3] & 0xFF,
device->mac_addr[4] & 0xFF,
device->mac_addr[5] & 0xFF);
/* ****************** */
printf("Setting %s device address...\n", device->ifName);
if ( 0 == strcmp("dhcp", address_mode) )
{
_snprintf(cmd, sizeof(cmd),
"netsh interface ip set address \"%s\" dhcp",
device->ifName);
}
else
{
_snprintf(cmd, sizeof(cmd),
"netsh interface ip set address \"%s\" static %s %s",
device->ifName, device_ip, device_mask);
}
if(system(cmd) == 0) {
device->ip_addr = inet_addr(device_ip);
device->device_mask = inet_addr(device_mask);
printf("Device %s set to %s/%s\n",
device->ifName, device_ip, device_mask);
} else
printf("WARNING: Unable to set device %s IP address [%s]\n",
device->ifName, cmd);
/* ****************** */
if(device->mtu != DEFAULT_MTU)
printf("WARNING: MTU set is not supported on Windows\n");
/* set driver media status to 'connected' (i.e. set the interface up) */
if (!DeviceIoControl (device->device_handle, TAP_IOCTL_SET_MEDIA_STATUS,
&status, sizeof (status),
&status, sizeof (status), &len, NULL))
printf("WARNING: Unable to enable TAP adapter\n");
/*
* Initialize overlapped structures
*/
device->overlap_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
device->overlap_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!device->overlap_read.hEvent || !device->overlap_write.hEvent) {
return -1;
}
return(0);
}
/* ************************************************ */
int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len)
{
DWORD read_size, last_err;
ResetEvent(tuntap->overlap_read.hEvent);
if (ReadFile(tuntap->device_handle, buf, len, &read_size, &tuntap->overlap_read)) {
//printf("tun_read(len=%d)\n", read_size);
return read_size;
}
switch (last_err = GetLastError()) {
case ERROR_IO_PENDING:
WaitForSingleObject(tuntap->overlap_read.hEvent, INFINITE);
GetOverlappedResult(tuntap->device_handle, &tuntap->overlap_read, &read_size, FALSE);
return read_size;
break;
default:
printf("GetLastError() returned %d\n", last_err);
break;
}
return -1;
}
/* ************************************************ */
int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len)
{
DWORD write_size;
//printf("tun_write(len=%d)\n", len);
ResetEvent(tuntap->overlap_write.hEvent);
if (WriteFile(tuntap->device_handle,
buf,
len,
&write_size,
&tuntap->overlap_write)) {
//printf("DONE tun_write(len=%d)\n", write_size);
return write_size;
}
switch (GetLastError()) {
case ERROR_IO_PENDING:
WaitForSingleObject(tuntap->overlap_write.hEvent, INFINITE);
GetOverlappedResult(tuntap->device_handle, &tuntap->overlap_write,
&write_size, FALSE);
return write_size;
break;
default:
break;
}
return -1;
}
/* ************************************************ */
int tuntap_open(struct tuntap_dev *device,
char *dev,
const char *address_mode, /* static or dhcp */
char *device_ip,
char *device_mask,
const char * device_mac,
int mtu) {
return(open_wintap(device, address_mode, device_ip, device_mask, device_mac, mtu));
}
/* ************************************************ */
void tuntap_close(struct tuntap_dev *tuntap) {
CloseHandle(tuntap->device_handle);
}
/* Fill out the ip_addr value from the interface. Called to pick up dynamic
* address changes. */
void tuntap_get_address(struct tuntap_dev *tuntap)
{
}
/* ************************************************ */
#if 0
int main(int argc, char* argv[]) {
struct tuntap_dev tuntap;
int i;
int mtu = 1400;
printf("Welcome to n2n\n");
initWin32();
open_wintap(&tuntap, "static", "1.2.3.20", "255.255.255.0", mtu);
for(i=0; i<10; i++) {
u_char buf[MTU];
int rc;
rc = tun_read(&tuntap, buf, sizeof(buf));
buf[0]=2;
buf[1]=3;
buf[2]=4;
printf("tun_read returned %d\n", rc);
rc = tun_write(&tuntap, buf, rc);
printf("tun_write returned %d\n", rc);
}
// rc = tun_open (device->device_name, IF_MODE_TUN);
WSACleanup ();
return(0);
}
#endif

67
win32/wintap.h Normal file
View File

@ -0,0 +1,67 @@
/*
(C) 2007 - Luca Deri <deri@ntop.org>
*/
#ifndef _WINTAP_H_
#define _WINTAP_H_
#undef UNICODE
#undef _UNICODE
#define _CRT_SECURE_NO_WARNINGS
#include <ws2tcpip.h>
#include <stdio.h>
#include <string.h>
//===============================================
// 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"
extern void initWin32();
#endif

461
wire.c Normal file
View File

@ -0,0 +1,461 @@
/* (c) 2009 Richard Andrews <andrews@ntop.org> */
/** Routines for encoding and decoding n2n packets on the wire.
*
* encode_X(base,idx,v) prototypes are inspired by the erlang internal
* encoding model. Passing the start of a buffer in base and a pointer to an
* integer (initially set to zero). Each encode routine increases idx by the
* amount written and returns the amount written. In this way complex sequences
* of encodings can be represented cleanly. See encode_register() for an
* example.
*/
#include "n2n_wire.h"
#include <string.h>
int encode_uint8( uint8_t * base,
size_t * idx,
const uint8_t v )
{
*(base + (*idx)) = (v & 0xff);
++(*idx);
return 1;
}
int decode_uint8( uint8_t * out,
const uint8_t * base,
size_t * rem,
size_t * idx )
{
if (*rem < 1 ) { return 0; }
*out = ( base[*idx] & 0xff );
++(*idx);
--(*rem);
return 1;
}
int encode_uint16( uint8_t * base,
size_t * idx,
const uint16_t v )
{
*(base + (*idx)) = ( v >> 8) & 0xff;
*(base + (1 + *idx)) = ( v & 0xff );
*idx += 2;
return 2;
}
int decode_uint16( uint16_t * out,
const uint8_t * base,
size_t * rem,
size_t * idx )
{
if (*rem < 2 ) { return 0; }
*out = ( base[*idx] & 0xff ) << 8;
*out |= ( base[1 + *idx] & 0xff );
*idx += 2;
*rem -= 2;
return 2;
}
int encode_uint32( uint8_t * base,
size_t * idx,
const uint32_t v )
{
*(base + (0 + *idx)) = ( v >> 24) & 0xff;
*(base + (1 + *idx)) = ( v >> 16) & 0xff;
*(base + (2 + *idx)) = ( v >> 8) & 0xff;
*(base + (3 + *idx)) = ( v & 0xff );
*idx += 4;
return 4;
}
int decode_uint32( uint32_t * out,
const uint8_t * base,
size_t * rem,
size_t * idx )
{
if (*rem < 4 ) { return 0; }
*out = ( base[0 + *idx] & 0xff ) << 24;
*out |= ( base[1 + *idx] & 0xff ) << 16;
*out |= ( base[2 + *idx] & 0xff ) << 8;
*out |= ( base[3 + *idx] & 0xff );
*idx += 4;
*rem -= 4;
return 4;
}
int encode_buf( uint8_t * base,
size_t * idx,
const void * p,
size_t s)
{
memcpy( (base + (*idx)), p, s );
*idx += s;
return s;
}
/* Copy from base to out of size bufsize */
int decode_buf( uint8_t * out,
size_t bufsize,
const uint8_t * base,
size_t * rem,
size_t * idx )
{
if (*rem < bufsize ) { return 0; }
memcpy( out, (base + *idx), bufsize );
*idx += bufsize;
*rem -= bufsize;
return bufsize;
}
int encode_mac( uint8_t * base,
size_t * idx,
const n2n_mac_t m )
{
return encode_buf( base, idx, m, N2N_MAC_SIZE );
}
int decode_mac( uint8_t * out, /* of size N2N_MAC_SIZE. This clearer than passing a n2n_mac_t */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
return decode_buf( out, N2N_MAC_SIZE, base, rem, idx );
}
int encode_common( uint8_t * base,
size_t * idx,
const n2n_common_t * common )
{
uint16_t flags=0;
encode_uint8( base, idx, N2N_PKT_VERSION );
encode_uint8( base, idx, common->ttl );
flags = common->pc & N2N_FLAGS_TYPE_MASK;
flags |= common->flags & N2N_FLAGS_BITS_MASK;
encode_uint16( base, idx, flags );
encode_buf( base, idx, common->community, N2N_COMMUNITY_SIZE );
return -1;
}
int decode_common( n2n_common_t * out,
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t idx0=*idx;
uint8_t dummy=0;
decode_uint8( &dummy, base, rem, idx );
if ( N2N_PKT_VERSION != dummy )
{
return -1;
}
decode_uint8( &(out->ttl), base, rem, idx );
decode_uint16( &(out->flags), base, rem, idx );
out->pc = ( out->flags & N2N_FLAGS_TYPE_MASK );
out->flags &= N2N_FLAGS_BITS_MASK;
decode_buf( out->community, N2N_COMMUNITY_SIZE, base, rem, idx );
return (*idx - idx0);
}
int encode_sock( uint8_t * base,
size_t * idx,
const n2n_sock_t * sock )
{
int retval=0;
uint16_t f;
switch (sock->family)
{
case AF_INET:
{
f = 0;
retval += encode_uint16(base,idx,f);
retval += encode_uint16(base,idx,sock->port);
retval += encode_buf(base,idx,sock->addr.v4,IPV4_SIZE);
break;
}
case AF_INET6:
{
f = 0x8000;
retval += encode_uint16(base,idx,f);
retval += encode_uint16(base,idx,sock->port);
retval += encode_buf(base,idx,sock->addr.v6,IPV6_SIZE);
break;
}
default:
retval=-1;
}
return retval;
}
int decode_sock( n2n_sock_t * sock,
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t * idx0=idx;
uint16_t f;
decode_uint16( &f, base, rem, idx );
if( f & 0x8000 )
{
/* IPv6 */
sock->family = AF_INET6;
decode_uint16( &(sock->port), base, rem, idx );
decode_buf( sock->addr.v6, IPV6_SIZE, base, rem, idx );
}
else
{
/* IPv4 */
sock->family = AF_INET;
decode_uint16( &(sock->port), base, rem, idx );
memset( sock->addr.v6, 0, IPV6_SIZE ); /* so memcmp() works for equality. */
decode_buf( sock->addr.v4, IPV4_SIZE, base, rem, idx );
}
return (idx-idx0);
}
int encode_REGISTER( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_t * reg )
{
int retval=0;
retval += encode_common( base, idx, common );
retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE );
retval += encode_mac( base, idx, reg->srcMac );
retval += encode_mac( base, idx, reg->dstMac );
if ( 0 != reg->sock.family )
{
retval += encode_sock( base, idx, &(reg->sock) );
}
return retval;
}
int decode_REGISTER( n2n_REGISTER_t * reg,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t retval=0;
memset( reg, 0, sizeof(n2n_REGISTER_t) );
retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx );
retval += decode_mac( reg->srcMac, base, rem, idx );
retval += decode_mac( reg->dstMac, base, rem, idx );
if ( cmn->flags & N2N_FLAGS_SOCKET )
{
retval += decode_sock( &(reg->sock), base, rem, idx );
}
return retval;
}
int encode_REGISTER_SUPER( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_SUPER_t * reg )
{
int retval=0;
retval += encode_common( base, idx, common );
retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE );
retval += encode_mac( base, idx, reg->edgeMac );
retval += encode_uint16( base, idx, 0 ); /* NULL auth scheme */
retval += encode_uint16( base, idx, 0 ); /* No auth data */
return retval;
}
int decode_REGISTER_SUPER( n2n_REGISTER_SUPER_t * reg,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t retval=0;
memset( reg, 0, sizeof(n2n_REGISTER_SUPER_t) );
retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx );
retval += decode_mac( reg->edgeMac, base, rem, idx );
retval += decode_uint16( &(reg->auth.scheme), base, rem, idx );
retval += decode_uint16( &(reg->auth.toksize), base, rem, idx );
retval += decode_buf( reg->auth.token, reg->auth.toksize, base, rem, idx );
return retval;
}
int encode_REGISTER_ACK( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_ACK_t * reg )
{
int retval=0;
retval += encode_common( base, idx, common );
retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE );
retval += encode_mac( base, idx, reg->dstMac );
retval += encode_mac( base, idx, reg->srcMac );
/* The socket in REGISTER_ACK is the socket from which the REGISTER
* arrived. This is sent back to the sender so it knows what its public
* socket is. */
if ( 0 != reg->sock.family )
{
retval += encode_sock( base, idx, &(reg->sock) );
}
return retval;
}
int decode_REGISTER_ACK( n2n_REGISTER_ACK_t * reg,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t retval=0;
memset( reg, 0, sizeof(n2n_REGISTER_ACK_t) );
retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx );
retval += decode_mac( reg->dstMac, base, rem, idx );
retval += decode_mac( reg->srcMac, base, rem, idx );
/* The socket in REGISTER_ACK is the socket from which the REGISTER
* arrived. This is sent back to the sender so it knows what its public
* socket is. */
if ( cmn->flags & N2N_FLAGS_SOCKET )
{
retval += decode_sock( &(reg->sock), base, rem, idx );
}
return retval;
}
int encode_REGISTER_SUPER_ACK( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_SUPER_ACK_t * reg )
{
int retval=0;
retval += encode_common( base, idx, common );
retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE );
retval += encode_mac( base, idx, reg->edgeMac );
retval += encode_uint16( base, idx, reg->lifetime );
retval += encode_sock( base, idx, &(reg->sock) );
retval += encode_uint8( base, idx, reg->num_sn );
if ( reg->num_sn > 0 )
{
/* We only support 0 or 1 at this stage */
retval += encode_sock( base, idx, &(reg->sn_bak) );
}
return retval;
}
int decode_REGISTER_SUPER_ACK( n2n_REGISTER_SUPER_ACK_t * reg,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t retval=0;
memset( reg, 0, sizeof(n2n_REGISTER_SUPER_ACK_t) );
retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx );
retval += decode_mac( reg->edgeMac, base, rem, idx );
retval += decode_uint16( &(reg->lifetime), base, rem, idx );
/* Socket is mandatory in this message type */
retval += decode_sock( &(reg->sock), base, rem, idx );
/* Following the edge socket are an array of backup supernodes. */
retval += decode_uint8( &(reg->num_sn), base, rem, idx );
if ( reg->num_sn > 0 )
{
/* We only support 0 or 1 at this stage */
retval += decode_sock( &(reg->sn_bak), base, rem, idx );
}
return retval;
}
int fill_sockaddr( struct sockaddr * addr,
size_t addrlen,
const n2n_sock_t * sock )
{
int retval=-1;
if ( AF_INET == sock->family )
{
if ( addrlen >= sizeof(struct sockaddr_in) )
{
struct sockaddr_in * si = (struct sockaddr_in *)addr;
si->sin_family = sock->family;
si->sin_port = htons( sock->port );
memcpy( &(si->sin_addr.s_addr), sock->addr.v4, IPV4_SIZE );
retval=0;
}
}
return retval;
}
int encode_PACKET( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_PACKET_t * pkt )
{
int retval=0;
retval += encode_common( base, idx, common );
retval += encode_mac( base, idx, pkt->srcMac );
retval += encode_mac( base, idx, pkt->dstMac );
if ( 0 != pkt->sock.family )
{
retval += encode_sock( base, idx, &(pkt->sock) );
}
retval += encode_uint16( base, idx, pkt->transform );
return retval;
}
int decode_PACKET( n2n_PACKET_t * pkt,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t retval=0;
memset( pkt, 0, sizeof(n2n_PACKET_t) );
retval += decode_mac( pkt->srcMac, base, rem, idx );
retval += decode_mac( pkt->dstMac, base, rem, idx );
if ( cmn->flags & N2N_FLAGS_SOCKET )
{
retval += decode_sock( &(pkt->sock), base, rem, idx );
}
retval += decode_uint16( &(pkt->transform), base, rem, idx );
return retval;
}