New upstream version 3.1.1

This commit is contained in:
billchenchina 2022-11-15 08:50:35 +08:00
parent 4e9934e5ec
commit e7b41df57b
229 changed files with 57000 additions and 12055 deletions

41
doc/Advanced.md Normal file
View file

@ -0,0 +1,41 @@
# Advanced Configuration
## Configuration Files
Read about [Configuration Files](ConfigurationFiles.md) as they might come in handy especially, but not limited to, if edges or supernodes shall be run as a service (see below) or in case of bulk automated parameter generation for mass deployment.
## Running edge as a Service
edge can also be run as a service instead of cli:
1. Edit `/etc/n2n/edge.conf` with your custom options. See `/etc/n2n/edge.conf.sample`.
2. Start the service: `sudo systemctl start edge`
3. Optionally enable edge start on boot: `sudo systemctl enable edge`
You can run multiple edge service instances by creating `/etc/n2n/edge-instance1.conf` and
starting it with `sudo systemctl start edge@instance1`.
## Communities
You might be interested to learn some [details about Communities](Communities.md) and understand how to limit supernodes' services to only a specified set of communities.
## Federation
It is available a special community which provides interconnection between supernodes. Details about how it works and how you can use it are available in [Federation](Federation.md).
## Virtual Network Device Configuration
The [TAP Configuration Guide](TapConfiguration.md) contains hints on various settings that can be applied to the virtual network device, including IPv6 addresses as well as notes on MTU and on how to draw IP addresses from DHCP servers.
## Routing the Traffic
Reaching a remote network or tunneling all the internet traffic via n2n are two common tasks which require a proper routing setup. n2n supports routing needs providing options for packet forwarding (`-r`) including broadcasts (`-E`) as well as temporarily modifying the routing table (`-n`). Details can be found in the [Routing document](Routing.md).
## Traffic Restrictions
It is possible to drop or accept specific packet transmit over edge network interface by rules. Rules can be specify by (`-R rule_str`) multiple times. Details can be found in the [Traffic Restrictions](TrafficRestrictions.md).

105
doc/Authentication.md Normal file
View file

@ -0,0 +1,105 @@
# Edge Authentication
From a discussion on how to prevent MAC address spoofing, the need of edge authentication became evident. In fact, the REGISTER_SUPER type messages already have shown a so far unused `auth` field which gets used for the first time starting in the course of n2n version 2.9 development.
## Implementation
n2n implements two different authentication schemes the user can chose from.
### Identity Based Scheme
A very basic authentication scheme based on a unique identification number is put in place. This ID is randomly generated during edge start-up and remains unchanged until the edge terminates. With every REGISTER_SUPER, it is transmitted to the supernode which remembers it from the first REGISTER_SUPER and can compare it to all the following ones. It is a verification based on "showing the ID". The supernode accepts REGISTER_SUPER (and thus changed MAC address or internet socket) and UNREGISTER type messages only if verification passes.
This does not only prevent UNREGISTER attacks but also MAC spoofing even in case of several federated supernodes because each REGISTER_SUPER message is forwarded to all other supernodes. If a new edge (un)intentionally tries to claim a MAC address which already has been in use by another edge, this would be detected as unauthorized MAC change because the new edge presents a different authentication ID. The supernode which rejects it (based on a failed comparison) sends a REGISTER_SUPER_**NAK** type message to the new edge as well as the supernode through which the new edge tried to register. The REGISTER_SUPER_NAK will cause the edge to output an ERROR message, it does not stop the edge anymore to prevent de-auth attacks.
As opposed to the MAC address which is sent out with each packet also between edges, the ID remains between the edge and the supernode. Other edges do not become aware of it and thus are not able to spoof.
A somewhat hurdling network sniffing attack aimed at observing the authentication ID could break this scheme. Thus, further development towards a more sophisticated crypto-based authentication scheme is intended.
In case of edges unexpectedly shutting down with no opportunity for a clean exit, this auth scheme prevents re-connection to the supernode until it internally is removed from the list (after some 90 seconds or so). Although `-M` command line option at the supernode can disable authentication ID comparison to circumvent this situation, usage of user / password based authentication scheme is highly recommended instead.
### User / Password Based Authentication
A more advanced scheme relies on username and especially password. Public key cryptography, namely Curve25519, ensures safety. Basically, the password along with the mixed in user name, serve as private key. The corresponding public key is generated by the `tools/n2n-keygen` utility. The such generated public key gets depoisted at the supernode.
#### Supernode Preparation
To generate a public key for the user `logan` and her very secret password `007`, the `tools/n2n-keygen` utility would be called with username and password as command line parameter:
```bash
[user@machine n2n]$ tools/n2n-keygen logan 007
* logan nHWum+r42k1qDXdIeH-WFKeylK5UyLStRzxofRNAgpG
```
The generated output line of format `* <username> <public key>` needs to be copied to the supernode's community list file, e.g. to the exemplary `community.list` file.
```
#
# List of allowed communities
# ---------------------------
#
# these could either be fixed-name communities such as the following lines ...
#
mynetwork
netleo
* logan nHWum+r42k1qDXdIeH-WFKeylK5UyLStRzxofRNAgpG
* sister HwHpPrdMft+38tFDDiunUds6927t0+zhCMMkQdJafcC
#
# ... or regular expressions that a community name must fully match
# such as ntop[0-1][0-9] for communities from "ntop00" through "ntop19"
#
ntop[0-1][0-9]
...
```
This example also lists another user `sister` (with the same secret password `007`). The users become part of the preceding community name, `netleo` in this case. The public keys are cryptographically tied only to the user name, not to the community name. That way, to switch a user from one community to another, her line can easily be copied from one community section to another. By the way, do not forget to provide the `community.list` file to the supernode through the `-c community.list` parameter.
Current supernode behavior does not limit the simultaneous usage of usernames, i.e. one username can be used from several edges at the same time. However, it is recommended to use a distinct username and password for each edge or computer. Your management port output will be much more meaningful then with the `HINT` column showing the related username. Also, the auto IP address feature, i.e. not using `-a <IP address>` at the edge, will more likely assign unique addresses as those depend on the username.
If a user chooses a new password or needs to be excluded from accessing the community (stolen edge scenario), the corresponding line of the `community.list` file can be replaced with a newly generated one or be deleted respectively. Restarting the supernode or issuing the `reload_communities` command to the management port is required after performing changes to make the supernode(s) read in this data again.
When using this feature federation-wide, i.e. across several supernodes, please make sure to keep all supernodes' `community.list` files in sync. So, if you delete or change a user one supernode (or add it), you need to do it at all supernodes. There is no built-in sync for the `community.list` files across the federation. External tools such as _Syncthing_ or your very own script-driven scp-based-file-distribution might be of assistance. Also, with every change, you need to restart the supernode or issue the `reload_communites` command to the management port as outlined above.
With a view to the detailed explanations below, your supernode(s) should have a non-default federation name given by the `-F <federation name>` command line parameter, e.g. `-F secretFed`. Alternatively, it can be passed through the environment variable `N2N_FEDERATION`. It is used to derive a private key at the supernode side and is only to be shared among supernodes.
#### Edge
The edge takes the username with the already present, identifying command line parameter `-I <username>`. The password goes into `-J <password>`. Continuing the given example, the edge is invoked by
```
[user@host n2n]$ sudo ./edge -l <supernode:port> -c netleo -I logan -J 007 <your additional parameters>
```
Note that header encryption already is enabled automatically as this authentication scheme heavily relies on it. Also, currently only the stream ciphers work with this authentication scheme reliably in terms of security. So, `-A4` for ChaCha20 or `-A5` for SPECK along with a key `-k <key>` are required as additional parameters.
The edges need to know the public key of the supernode. By default, the edges assume the default federation name, or more specific, the corresponding public key. In case the supernode is given a custom federation name which is highly recommended, the supernode's public key is provided to the edges via command line parameter `-P <public key>`. It can be generated from the federation name by using the `tools/n2n-keygen` utility as well:
```bash
[user@host n2n]$ tools/n2n-keygen -F secretFed
-P opIyaWhWjKLJSNOHNpKnGmelhHWRqkmY5pAx7lbDHp4
```
Considering all this, our example expands to
```
[user@host n2n]$ sudo ./edge -l <supernode:port> -c netleo -I logan -J 007 -A5 -k mySecretKey -P opIyaWhWjKLJSNOHNpKnGmelhHWRqkmY5pAx7lbDHp4
```
You might want to consider the use of [`.conf` files](https://github.com/ntop/n2n/blob/dev/doc/ConfigurationFiles.md) to accomodate all the command line parameters more easily. Alternatively, the `N2N_PASSWORD` environment variable can be used to set the password without having it show up as part of the command line.
#### How Does It Work?
In order to make this authentication scheme work, the existing header encryption scheme is split into using two keys: a _static_ and a _dynamic_ one. The static key remains unchanged and is the [classic header encryption key](https://github.com/ntop/n2n/blob/dev/doc/Crypto.md#header) derived from the community name. It only is applied to the very basic registration traffic between edge and supernode (REGISTER_SUPER, REGISTER_SUPER_ACK, REGISTER_SUPER_NAK). The dynamic key is derived (among others) from the federation name keep it secret! and applied to all the other packets, especially the data packets (PACKET) and peer-to-peer building packets (REGISTER), but also the ping and peer information (QUERY_PEER, PEER_INFO). An edge not provided with a valid dynamic key is not able to participate in the further communication.
In regular header encryption mode, static key and dynamic key are equal. With activated user-password scheme, the supernode generates and transmits a dynamic key with the REGISTER_SUPER for further use. This happens in a secure way based on public key cryptography. A non-authenticated edge, i.e. without corresponding entry at the supernode or valid credentials, will not receive a valid dynmic key for communication beyond registration.
In user-password scheme, the packets encrypted with the static key (REGISTER_SUPER, REGISTER_SUPER_ACK, useless for REGISTER_SUPER_NAK) are "signed" with an encrypted outer hash using the shared secret which is only known to the federated supernodes and that specific edge.
#### Possible Extensions
Tools for automizing [`.conf` file](https://github.com/ntop/n2n/blob/dev/doc/ConfigurationFiles.md) generation for deployment ot delivery to freshly registered and approved users could greatly enhance this ecosystem; a user would not have to mess around with command line parameters but just copy a `.conf` file into a specified directory.
Let us know if you are interested in implementing or furthering these ideas.

185
doc/BuildConfig.md Normal file
View file

@ -0,0 +1,185 @@
# Configuration at Build time
There are a number of configuration options that are made only at build time.
In order to assist with cross compilation, minimising test cases, repeatable
builds and minimising externalities, the build options are generally defaulted
to off.
As part of simplifying cross compilation, the use of auto-detected
configuration settings are being removed.
## Options
After changing any configuration, please do no forget to `make clean` after
the (re-)configuration and before building (again) using `make`. (Or the
equivalent with `cmake`)
### `--with-zstd`
ZSTD Compression Support
In addition to the built-in LZO1x for payload compression (`-z1` at the edge's
commandline), n2n optionally supports [ZSTD](https://github.com/facebook/zstd).
As of 2020, it is considered cutting edge and [praised](https://en.wikipedia.org/wiki/Zstandard)
for reaching the currently technologically possible Pareto frontier in terms
of CPU power versus compression ratio.
#### Makefile
ZSTD support can be configured using
`./configure --with-zstd`
which then will include ZSTD. It will be available via `-z2` at the edges. Of course, it can be combined with the other optimisation features:
`./configure --with-zstd --with-openssl CFLAGS="-O3 -march=native"`
Again, and this needs to be reiterated sufficiently often, please do no forget to `make clean` after (re-)configuration and before building (again) using `make`.
### `--with-openssl`
Use openssl instead of the built-in AES code
The speed of some ciphers' can take advantage of OpenSSL support This is
disabled by default as the built-in ciphers already prove reasonably fast
in most cases.
When enabled, this will include OpenSSL 1.1. This can also be combined with
the hardware support and compiler optimizations such as.
`./configure --with-openssl CFLAGS="-O3 -march=native"`
#### Makefile
Add `--with-openssl` to the `configure` command
#### Cmake
Add `-DN2N_OPTION_USE_OPENSSL=ON` to the cmake configure step.
Additionally, it is possible to statically link the OpenSSL library.
Add `-DOPENSSL_USE_STATIC_LIBS=true` to the cmake configure step.
Building statically with openssl in this way has been known to have
issues recently on Windows (See #944)
### `--with-edgex`
A legacy option intended to help cross compilation - if you use this option
please let us know as there are probably more modern options for
cross-compiling
### `--enable-pthread`
Enable threading using the pthread library
### `--enable-cap`
Use the libcap to provide reduction of the security privileges needed in the
running daemon
### `--enable-pcap`
If the pcap library is available then the `n2n-decode` tool can be compiled.
### `--enable-natpmp`
One of the two UPnP libraries, this one supports the NATPMP protocol.
See also the next option.
This option depends on the library being installed - on Debian and Ubuntu,
this is `apt-get install libnatpmp-dev`
### `--enable-miniupnp`
Enables the other kind of UPnP port mapping protocol.
Turning on either of these two UPnP libraries will enable UPnP support within
the edge.
Both the natpmp and miniupnp depend on the pthread library being enabled.
This option depends on the library being installed - on Debian and Ubuntu,
this is `apt-get install libminiupnpc-dev`
### Disable Multicast Local Peer Detection
For better local peer detection, the edges try to detect local peers by sending REGISTER
packets to a certain multicast address. Also, edges listen to this address to eventually
fetch such packets.
If these packets disturb network's peace or even get forwarded by (other) edges through the
n2n network, this behavior can be disabled
#### Makefile
Add
`-DSKIP_MULTICAST_PEERS_DISCOVERY`
to your `CFLAGS` when configuring, e.g.
`./configure --with-zstd CFLAGS="-O3 -march=native -DSKIP_MULTICAST_PEERS_DISCOVERY"`
### Deprecation of --with options
Due to historical reasons, the autoconf system does not validate the syntax
of any `--with-X` style options, thus to provide the highest confidence in
the correctness of configuration and compilation, `--enable-X` style options
are preferred. As part of this, the older `--with-X` options will eventually
be migrated to use `--enable-X`
## CMake configuration
There are a number of OPTION statements in the CMakeLists.txt file that can
have their settings changed. This is done by adding a commandline option
to the cmake configure stage.
e.g:
`cmake -DN2N_OPTION_USE_ZSTD=ON ..`
Note that the names of the configure option variables used in the cmake
process will probably change to make the source code consistent.
# Optimisation options
## Compiler Optimizations
The easiest way to boosting speed is by allowing the compiler to apply optimization to the code. To let the compiler know, the configuration process can take in the optionally specified compiler flag `-O3`:
`./configure CFLAGS="-O3"`
The `tools/n2n-benchmark` tool reports speed-ups of 200% or more! There is no known risk in terms of instable code or so.
## Hardware Features
Some parts of the code significantly benefit from compiler optimizations (`-O3`) and platform features
such as NEON, SSE and AVX. It needs to be decided at compile-time. Hence if compiling for a specific
platform with known features (maybe the local one), it should be specified to the compiler for
example through the `-march=sandybridge` (you name it) or just `-march=native` for local use.
So far, the following portions of n2n's code benefit from hardware features:
```
AES: AES-NI
ChaCha20: SSE2, SSSE3
SPECK: SSE2, SSSE3, AVX2, AVX512, (NEON)
Random Numbers: RDSEED, RDRND (not faster but more random seed)
```
The compilations flags could easily be combined:
`./configure CFLAGS="-O3 -march=native"`.
There are reports of compile errors showing `n2n_seed': random_numbers.c:(.text+0x214): undefined reference to _rdseed64_step'` even though the CPU should support it, see #696. In this case, best solution found so far is to disable `RDSEED` support by adding `-U__RDSEED__` to the `CFLAGS`.
## SPECK ARM NEON Hardware Acceleration
By default, SPECK does not take advantage of ARM NEON hardware acceleration even if compiled with `-march=native`. The reason is that the NEON implementation proved to be slower than the 64-bit scalar code on Raspberry Pi 3B+, see [here](https://github.com/ntop/n2n/issues/563).
Your specific ARM mileage may vary, so it can be enabled by configuring the definition of the `SPECK_ARM_NEON` macro:
`./configure CFLAGS="-DSPECK_ARM_NEON"`
Just make sure that the correct architecture is set, too. `-march=native` usually works quite well.

173
doc/Building.md Normal file
View file

@ -0,0 +1,173 @@
This document describes the process for compiling n2n in several different
scenarios.
There are some configuration options available during the build process,
which are documented in the [Build time Configuration](BuildConfig.md) page.
Also of use are the steps used for the automated Continuous Integration
process, which can be found in the [Github actions config file](../.github/workflows/tests.yml)
# Git submodules
If you are compiling with the UPnP libraries, it is possible that your
operating system or your build system do not include binaries for the
required libraries.
Using these libraries can cause issues with some build systems, so be
aware that not all combinations are supportable.
To make this scenario simpler, the required source code has been added
to this repository as git `submodules` which require one extra step to
complete their checkout.
So the very first time after cloning the n2n git repo, you should run
this command in the n2n directory to fetch the submodules:
```bash
git submodule update --init --recursive
```
# Build on macOS
In order to use n2n on macOS, you first need to install support for TUN/TAP interfaces:
```bash
brew tap homebrew/cask
brew cask install tuntap
```
If you are on a modern version of macOS (i.e. Catalina), the commands above will ask you to enable the TUN/TAP kernel extension in System Preferences → Security & Privacy → General.
For more information refer to vendor documentation or the [Apple Technical Note](https://developer.apple.com/library/content/technotes/tn2459/_index.html).
Note that on the newest MacOS versions and on Apple Silicon, there may be
increasing security restrictions in the OS that make installing the TUN/TAP
kernel extension difficult. Alternative software implementations to avoid
these difficulties are being discussed for future n2n versions.
# Build on Windows
The following document some possible windows compile recipes. Of them, the
MinGW build process is more tested as it is more friendly to open source
development.
## Visual Studio
### Requirements
In order to build with Vidual Studio on Windows the following tools should be installed:
- Visual Studio. For a minimal install, the command line only build tools can be
downloaded and installed from https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2017.
- CMake (From https://cmake.org/download/)
NOTE: You should always use the official cmake stable release as otherwise
you may have issues finding libraries (e.g: the installed OpenSSL library).
If you still have problems, you can try invoking it with `C:\Program Files\CMake\bin\cmake`.
- (optional) The OpenSSL library. This optional library can be enabled as
per the steps in the [Build time Configuration](BuildConfig.md)
Pre-built OpenSSL binaries can be downloaded from
https://slproweb.com/products/Win32OpenSSL.html.
The full version is required, i.e. not the "Light" version. The Win32
version of it is usually required for a standard build.
### CLI steps
In order to build from the command line, open a terminal window change to
the directory where the git checkout of this repository is and run the
following commands:
Building using `cmake` works as follows:
```batch
cmake -E make_directory build
cd build
rem Append any options to the next line
cmake ..
cmake --build . --config Release
```
The compiled `.exe` files should now be available in the `build\Release` directory.
## MinGW
These steps were tested on a fresh install of Windows 10 Pro with all patches
applied as of 2021-09-29.
- Install Chocolatey (Following instructions on https://chocolatey.org/install)
- from an admin cmd prompt
- `choco install git mingw make`
- All the remaining commands must be run from inside a bash shell ("C:\Program Files\Git\usr\bin\bash.exe")
- `git clone $THIS_REPO`
- `cd n2n`
- `./scripts/hack_fakeautoconf.sh`
- `make`
- `make test`
Due to limitations in the Windows environment, the normal autotools steps have
been emulated by the `hack_fakeautoconf` - This currently results in the
version number reported by the compiled software being inaccurate.
Note: MinGW builds have had a history of incompatibility reports with other OS
builds (for example [#617](https://github.com/ntop/n2n/issues/617) and [#642](https://github.com/ntop/n2n/issues/642))
However, if the tests pass, you should have a high confidence that your build
will be compatible.
## Run on Windows
In order to run n2n on Windows, you will need the following:
- The TAP drivers should be installed into the system. They can be installed from
http://build.openvpn.net/downloads/releases, search for "tap-windows".
- If OpenSSL has been linked dynamically, the corresponding `.dll` file should be available
onto the target computer.
The `edge.exe` program reads the `edge.conf` file located into the current directory if no option is provided.
The `supernode.exe` program reads the `supernode.conf` file located into the current directory if no option is provided.
Example [edge.conf](../packages/etc/n2n/edge.conf.sample)
and [supernode.conf](../packages/etc/n2n/supernode.conf.sample) are available.
See `edge.exe --help` and `supernode.exe --help` for a full list of supported options.
# Cross compiling on Linux
## Using the Makefiles and Autoconf
The Makefiles are all setup to allow cross compiling of this code. You
will need to have the cross compiler, binutils and any additional libraries
desired installed for the target architecture. Then you can run the `./configure`
with the appropriate CC and AR environment and the right `--host` option.
If compiling on Debian or Ubuntu, this can be as simple as the following example:
```
HOST_TRIPLET=arm-linux-gnueabi
sudo apt-get install binutils-$HOST_TRIPLET gcc-$HOST_TRIPLET
./autogen.sh
export CC=$HOST_TRIPLET-gcc
export AR=$HOST_TRIPLET-ar
./configure --host $HOST_TRIPLET
make
```
A good starting point to determine the host triplet for your destination platform
can be found by copying the `./config.guess` script to it and running it on the
destination.
This is not a good way to produce binaries for embedded environments (like OpenWRT)
as they will often use a different libc environment.
# N2N Packages
There are also some example package build recipes included with the source.
- [Debian](../packages/debian/README)
- [RPM](../packages/rpm)
- [OpenWRT](../packages/openwrt/README.md)

81
doc/Communities.md Normal file
View file

@ -0,0 +1,81 @@
# Communities
## Names
As communities designate virtual networks, they must be distinguishable from each other. Its their name that makes them distinguishable and which therefore should be unique per network. The community name is composed of 19 byte-sized characters and it internally always is terminated by an additional zero character totalling up to 20 characters. Hence, the zero character cannot be part of the regular community name. There are some other characters that cannot be used, namely `. * + ? [ ] \`.
To make full use of character space, hex values could be used, e.g. from Linux bash applying the `edge … -c $(echo -en '\x3a\x3b\x4a\x6a\xfa') …` command line syntax. If used with a configuration file, the bytes must be directly filled as characters into a corresponding `-c :;Jjþ` line.
Apart from command line `-c` and configuration file, the community name can be supplied through the `N2N_COMMUNITY` environment variable. This might prove useful to hide the community name from command line if used with header encryption enabled, see below.
## Restrict Supernode Access
By default, a supernode offers its service to all communities and allows them to connect. If a self-setup supernode shall handle certain communities only, the supernode can be given a list of allowed communities. This list is a simple text file containg the allowed community names, one per line:
```
# community.list (a text file)
-----------------------------------------------------
myCommunity
yourCommunity
```
This file is provided to the supernode through the `-c community.list` command line parameter. This example would allow the supernode to only accept connections from communities called "myCommunity" and "yourCommunity", these are fixed-name communities.
## Somewhat Flexible Community Names
If you want to allow all community names from a certain name range, e.g. from "myCommunity00" to "myCommunity99", the `community.list` file (or whatever you name it) could look as follows:
```
# community.list (a text file)
-----------------------------------------------------
myCommunity[0-9][0-9]
```
Advanced users recognize the so called regular expression. To prevent users from stop reading, the author did not dare to name this section "Regular Expressions". Anyway, community names can be provided as regular expressions using the following placeholders:
```
'.' Dot, matches any character
'*' Asterisk, match zero or more of previous element (greedy)
'+' Plus, match one or more of previous element (greedy)
'?' Question, match zero or one (non-greedy)
'[abc]' Character class, match if one of {'a', 'b', 'c'}
'[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} (feature is currently broken)
'[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z }
'\s' Whitespace, \t \f \r \n \v and spaces
'\S' Non-whitespace
'\w' Alphanumeric, [a-zA-Z0-9_]
'\W' Non-alphanumeric
'\d' Digits, [0-9]
'\D' Non-digits
```
Knowing this, we can as well express the exemplary `community.list` above the following way:
```
# community.list (a text file)
-----------------------------------------------------
myCommunity\d\d
```
Also, as the `. * + ? [ ] \` characters indicate parts of regular expressions, we now understand why those are not allowed in fixed-name community names.
## Header Encryption
By default, the community name is transmitted in plain witch each packet. So, a fixed-name community might keep your younger siblings out of your community (as long as they do not know the community name) but sniffing attackers will find out the community name. Using this name, they will be able to access it by just connecting to the supernode then.
[Header encryption](Crypto.md#header) can be enabled to prevent plain transmission. It is important to understand that header encryption, if enabled, only works on fixed-name communities. It will not work on community names described by regular expressions.
On the other hand, the provision of fixed-name communities blocks all other, non-listed communities. To allow a mixed operation of certain encrypted and hence fixed-name communities along with all other open communities, the following "trick" can be applied:
```
# community.list (a text file)
-----------------------------------------------------
mySecretCom
.*
```
This is not really a trick but just making use of a very permissive regular expression at the second line.

73
doc/ConfigurationFiles.md Normal file
View file

@ -0,0 +1,73 @@
# Configuration Files
To help deployment and better handle locally different configurations, n2n supports the optional use of configuration files for `edge` and `supernode`.
They are plain text files and contain the desired command line options, **one per line**.
The exemplary command line
```bash
sudo edge -c mynetwork -k mysecretpass -a 192.168.100.1 -f -l supernode.ntop.org:7777
```
translates into the following `edge.conf` file:
```
-c mynetwork
-k mysecretpass
-a 192.168.100.1
-f
-l supernode.ntop.org:7777
-A5
```
which can be loaded by
```
sudo ./edge edge.conf
```
Comment lines starting with a hash '#' are ignored.
```
# automated edge configuration
# created by bot7
# on April 31, 2038 1800Z
-c mynetwork
-k mysecretpass
-a 192.168.100.1
-f
-A5
# --- supernode section ---
-l supernode.ntop.org:7777
```
Long options can be used as well. Please note the double minus/dash-character `--`, just like you would use them on the command line with long options:
```
--community mynetwork
-k mysecretpass
-a 192.168.100.1
-f
-A5
-l supernode.ntop.org:7777
```
If using a configuration file, its filename needs to be supplied as first parameter to `edge` or `supernode`. If required, additional command line parameters can be supplied afterwards:
```
sudo edge edge.conf -z1 -I myComputer
```
Finally, the `.conf` file syntax also allows `=` between parameter and its option:
```
-c=mynetwork
-k=mysecretpass
-a=192.168.100.1
-f
-A5
-l=supernode.ntop.org:7777
```
When used with `=`, there is no whitespace allowed between parameter, delimiter (`=`), and option. So, do **not** put `-c = mynetwork` it is required to be `-c=mynetwork`.

216
doc/Crypto.md Normal file
View file

@ -0,0 +1,216 @@
# Cryptography in n2n
## Payload
### Overview
Payload encryption currently comes in four different flavors using ciphers of different origins. Supported ciphers are enabled using the indicated command line option:
- Twofish in CTS mode (`-A2`)
- AES in CBC mode (`-A3`)
- ChaCha20 (CTR) (`-A4`)
- SPECK in CTR mode (`-A5`)
The following chart might help to make a quick comparison and decide what cipher to use:
| Cipher | Mode | Block Size | Key Size | IV length |Speed | Built-In | Origin |
| :---: | :---:| :---: | :---: | :---: |:---: | :---: | --- |
|Twofish | CTS | 128 bits | 256 bit | 128 bit | -..O | Y | Bruce Schneier |
|AES | CTS | 128 bits | 128, 192, 256 bit| 128 bit | O..+ | Y | Joan Daemen, Vincent Rijmen, NSA-approved |
|ChaCha20| CTR | Stream | 256 bit | 128 bit | +..++| Y | Daniel J. Bernstein |
|SPECK | CTR | Stream | 256 bit | 128 bit | ++ | Y | NSA |
The two block ciphers Twofish and AES are used in CTS mode.
n2n has all four ciphers built-in as basic versions. Some of them optionally compile to faster versions by the means of available hardware support (AES-NI, SSE, AVX please see the [Building document](./Building.md) for details. Depending on your platform, AES and ChaCha20 might also draw notable acceleration from optionally compiling with openSSL 1.1 support.
The`-k <key>` command line parameter supplies the key. As even non-privileged users might get to see the command line parameters (try `ps -Af | grep edge`), the key can also be supplied through the `N2N_KEY` environment variable: `sudo N2N_KEY=mysecretpass edge -c mynetwork -a 192.168.100.1 -f -l supernode.ntop.org:7777`.
Providing `-k <key>` without specifying any cipher by `-A_` will default to AES encryption.
To renounce encryption, `-A1` enables the so called `null_transform` transmitting all payload data unencryptedly. Omitting `-A_` and not providing a key through `-k <key>` shows the same effect.
### Twofish
This implementation prepends a 128 bit random value to the plain text. Its size is adjustable by changing the `TF_PREAMBLE_SIZE` definition found in `src/transform_tf.c`. It defaults to TF_BLOCK_SIZE (== 16). As CTS uses underlying CBC mode, this basically has the same effect as a respectively shorter IV. However, this flexibility does not come for free as an additional block needs to be encrypted.
Twofish requires no padding as it employs a CBC/CTS scheme which can send out plaintext-length ciphertexts. The scheme however has a small flaw in handling messages shorter than one block, only low-level programmer might encounter this.
On Intel CPUs, Twofish usually is the slowest of the ciphers present. However, on Raspberry Pi 3B+, Twofish was observed to be faster than AES-CTS. Your mileage may vary. Cipher speed's can be compared running the `tools/n2n-benchmark` tool.
### AES
AES also prepends a random value to the plaintext. Its size is adjustable by changing the `AES_PREAMBLE_SIZE` definition found in `src/transform_aes.c`. It defaults to AES_BLOCK_SIZE (== 16). The AES scheme uses a CBC/CTS scheme which can send out plaintext-length ciphertexts as long as they are one block or more in length.
Apart from n2n's plain C implementation, Intel's AES-NI is supported again, please have a look at the [Building document](./Building.md). In case of openSSL support its `evp_*` interface gets used which also offers hardware acceleration where available (SSE, AES-NI, …). It however is slower than the following stream ciphers because the CBC mode cannot compete with the optimized stream ciphers.
This cipher's different key-sizes are triggered by the length of the user-provided key: 22 characters or less make n2n use AES-128, between 23 and 32 characters lead to AES-192, and 33 or more characters trigger AES-256.
### ChaCha20
ChaCha20 was the first stream cipher supported by n2n.
In addition to the basic C implementation, an SSE version is offered. If compiled with openSSL support, ChaCha20 is provided via the `evp_*` interface. It is not used together with the Poly1305 message tag from the same author though. Whole packet's checksum will be handled in the header (see below).
The random full 128-bit IV is transmitted in plain.
ChaCha20 usually performs faster than AES-CTS.
### SPECK
SPECK is recommended by the NSA for offical use in case AES implementation is not feasible due to system constraints (performance, size, …). The block cipher is used in CTR mode making it a stream cipher. The random full 128-bit IV is transmitted in plain.
On modern Intel CPUs, SPECK performs even faster than openSSL's ChaCha20 as it takes advantage of SSE4, AVX2, or AVX512 if available. On Raspberry's ARM CPU, it is second place behind ChaCha20 and before Twofish.
### Random Numbers
Throughout n2n, pseudo-random numbers are generated for several purposes, e.g. random MAC assignment and the IVs for use with the various ciphers. Regarding IVs, especially for using in the stream ciphers, the pseudo-random numbers shall be as collision-free as possible. n2n uses an implementation of XORSHIFT128+ which shows a periodicity of 2¹²⁸.
Its initialization relies on seeding with a value as random as possible. Various sources are tapped including a syscall to Linux' `SYS_getrandom` as well as Intels hardware random number generators `RDRND` and `RDSEED`, if available (compile using `-march=native`).
### Pearson Block Hashing
For general purpose hashing, n2n employs [Pearson Block Hashing](https://github.com/Logan007/pearsonB) as it offers variable hash sizes and is said not to be too "collidy". However, this is not a cryptographically secure hashing function which by the way is not required here: The hashing is never applied in a way that the hash value shall publicly prove the knowledge of a secret without showing the secret itself.
_Pearson hashing is tweakable by using your own block-sized permutation._ Here, we use a three-round xor-rotate-multiply permutation scheme on 64-bit wide integer numbers with constants discovered by [David Stafford](http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html) (`mix13`, permission obtained via eMail) which, meanwhile, is better known as part of `splitmix64()`.
_Pearson hashing allows verification of block-sized parts of the hash only just in case performance requirements would urge to do so._
## Header
### Overview
Packet's header consist of a COMMON section followed by a packet-type specific section, e.g. REGISTER, REGISTER_ACK, PACKET including the payload, REGISTER_SUPER, …
The COMMON section is built as follows:
```
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 = 3 ! TTL ! Flags !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 ! Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 ! ... Community !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
In case of a PACKET-type, it is succeeded by the fields depicted below:
```
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24 ! Source MAC Address :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28 : ! Destination MAC Address :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 : !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 ! Socket Flags (v=IPv4) ! Destination UDP Port !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 ! Destination IPv4 Address !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 ! Compress'n ID ! Transform ID ! Payload ... !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
48 ! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+...
```
### Encryption
If enabled (`-H`), all fields but the payload (which is handled separately as outlined above) get encrypted using SPECK in CTR mode. As packet headers need to be decryptable by the supernode and we do not want to add another key (to keep it a simple interface), the community name serves as key (keep it secret!) because it is already known to the supernode. The community name consists of up to 20 characters (well, 19 + `0x00`), so key size of 128 bit is a reasonable choice here.
The scheme applied tries to maintain compatibility with current packet format and works as follows:
- First line of 4 bytes (Version, TTL, Flags) goes to sixth line:
```
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 ! ... Community !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 ! Version = 3 ! TTL ! Flags !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
- To be able to identify a correctly decrpyted header later on, a magic number is stamped in fourth line starting at byte number 16. We use "n2" string and add the 16-bit header length to be able to stop header decryption right before an eventually following ethernet data payload begins in case of PACKET-type, header-length does not equal packet-length. 16-bit length is required because REGISTER_SUPER_ACK packets consist of header only and could grow quite large due to their payload (other supernodes of federation) don't mix up this kind of payload (part of the header) with the ethernet data payload of PACKET messages.
- The rest of the community field, namely the first 16 bytes, is reframed towards a 128-bit IV for the header encryption.
```
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! IV ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 ! ... IV ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 ! ... IV ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 ! ... IV !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 ! Magic Number "n2" = 0x6E32 ! Header Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 ! Version = 3 ! TTL ! Flags !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
- As we use a stream cipher, the IV should be a nonce. The IV plays an additional role sketched later, see the following sections on checksum and replay protection.
- To make a less predictable use of the key space just think of the typically reset MSB of ASCII characters of community names we actually use a hash of the community name as key.
- Encryption starts at byte number 16 and ends at header's end. It does not comprise PACKET's ethernet data payload which eventually has its own encryption scheme as chosen with the `-A_` options.
Decryption checks all known communities (several in case of supernode, only one at edge) as keys. On success, the emerging magic number along with a reasonable header's length value will reveal the correct community whose name will be copied back to the original fields allowing for regular packet handling.
Thus, header encryption will only work with previously determined community names introduced to the supernode by `-c <path>` parameter. Also, it should be clear that header encryption is a per-community decision, i.e. all nodes and the supernode need to have it enabled. However, the supernode supports encrypted and unencrypted communities in parallel, it determines their status online at arrival of the first packet. Use a fresh community name for encrypted communities; do not use a previously used one of former unecrypted communities: their names were transmitted openly.
### Checksum
The whole packet including the eventually present payload is checksummed using a Person block hashing scheme. The 64-bit checksum is exclusive-ored with a (shifted by 32 bit) 64-bit time stamp and filled up with 32 more random bits to obtain a 128-bit pre-IV. This pre-IV gets encrypted using a single block-cipher step to get the pseudo-random looking IV. This way, the checksum resists targeted bit-flips (to header, payload, and IV) as any change to the whole 128-bit IV would render the header un-decryptable. Also, as explained below, the checksum comes along with a time stamp minimizing opportunities for random attacks.
The single block-cipher step employs SPECK because it is quite fast and it offers a 128-bit block cipher version. The key is derived from the header key a hash of the hash.
The checksum is calculated by the edges and the supernode. Changes to the payload will cause a different locally calculated checksum. Extracting the time stamp by exclusive-oring an erroneous checksum will lead to an invalid timestamp. So, checksum errors are indirectly detected when checking for a valid time stamp.
### Replay Protection
The aforementioned 128-bit pre-IV can be depicted as follows:
```
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
+----------------------------------------------------------------+-------------------------------+-------------------------------+
! 64-bit checksum of the whole packet ! 0x00 ! !
+ - - - - - - - - - - - - - - - - - - - - - - - XOR - - - - - - - - - - - - - - - - - - - - - - -! 32 pseudo-random bits !
! 0x00 ! 52-bit time stamp with microsecond-accuracy ! countr ! F ! !
+------------------------------------------------------------------------------------------------+-------------------------------+
```
The time stamp consists of the 52-bit microsecond value, a 8-bit counter in case of equal following time stamps and, a 4-bit flag field F (accuracy indicator in last bit). edge and supernode monitor their own time stamps for doublets which would indicate an accuracy issue. If the counter overflows on the same time stamp, the sub-second part of the time stamp will also become counter. In this case, the whole stamp carries the accuracy bit flag (lowest bit) set so other edges and supernodes can handle this stamp appropriately.
Encrypting this pre-IV using a block cipher step will generate a pseudo-random looking IV which gets written to the packet and used for the header encryption.
Due to the time-stamp encoded, the IV will more likely be unique, close to a real nonce.
Upon receival, the time stamp as well as the checksum can be extracted from the IV by performing a 128-bit block-cipher decryption step. Verification of the time stamp happens in two steps:
- The (remote) time stamp is checked against the local clock. It may not deviate more than plus/minus 16 seconds. So, edges and supernode need to keep a somewhat current time. This limit can be adjusted by changing the `TIME_STAMP_FRAME` definition. It is time-zone indifferent as UTC is used.
- Valid (remote) time stamps get stored as "last valid time stamp" seen from each node (supernode and edges). So, a newly arriving packet's time stamp can be compared to the last valid one. It should be equal or higher. However, as UDP packets may overtake each other just by taking another path through the internet, they are allowed to be 160 millisecond earlier than the last valid one. This limit is set with the `TIME_STAMP_JITTER` definition. If the accuracy flag is set, the time stamp will be allowed a jitter eight times as high, corresponding to 1.25 seconds by default.
- However, the systemic packets such as REGISTER_SUPER are not allowed any time stamp jitter because n2n relies on the actual sender's socket. A replay from another IP within any allowed jitter time frame would deviate the traffic which shall be prevented (even if it remains undecryptable). Under absolutely rare (!) circumstances, this might cause a re-registration requirement which happens automatically but might cause a small delay security (including network availability) first! REGISTER packets from the local multicast environment are exempt from the very strict no-jitter requirement because they indeed regularly can show some deviation if compared to time stamps in packets received on the regular socket. As these packets are incoming on different sockets, their processing is more likely to no take place in the order these packets were sent.
The way the IV is used for replay protection and for checksumming makes enabled header encryption a prerequisite for these features.

72
doc/Faq.md Normal file
View file

@ -0,0 +1,72 @@
# n2n Frequently Asked Questions
## Supernode
### I want to setup a supernode that only I can use. Perhaps even password protected?
Please think of the community-name as password and start the supernode with the `-c <community file>` parameter where the `<community file>` is the path to a simple text file containing a single line with the name of your secret community. It will be the only community allowed. Only edge nodes from that community can join (`-c <community name>` at the edge).
If you additionally want to prevent open transmission of your secret community name via the network, **all** edge nodes should use `-H` command line option for header encryption.
Also, please see the `community.list` file coming with n2n for advanced use of that file.
Beyond this access barrier you may want to use payload encryption `-A_` at the edges. Only the edges not the supernode are able to decipher the payload data. So, even if anyone would be able to break the access barrier to the supernode, the payload remains protected by the payload crypto, see [this document](https://github.com/ntop/n2n/blob/dev/doc/Crypto.md) for details.
### Can I get a list of connected edge nodes and their community and source IP address from the supernode?
The supernode provides basic information via its localhost udp management port. It defaults to 5645 and can be changed using supernode's `-t` command line option.
You can request the current status by just sending a new line, i.e. pressing [ENTER] key, running the following command (localhost only)
`netcat -u localhost 5645`
### Is there support for multiple supernodes?
Yes, there is. Please [read](https://github.com/ntop/n2n/blob/dev/doc/Federation.md) about how several supernodes can form a Federation to increase network resilience.
### Can a supernode listen on multiple ports?
The supernode itself can only listen on one port. However, your firewall might be able to map additional UDP ports to the supernode's regular port:
`sudo iptables -t nat -A PREROUTING -i <network interface name> -d <supernode's ip address> -p udp --dport <additional port number> -j REDIRECT --to-ports <regular supernode port number>`
This command line can be put down as additional `ExecStartPost=` line (without `sudo`) in the supernode's `.service` file which can hold several such lines if required.
### How to handle the error message "process_udp dropped a packet with seemingly encrypted header for which no matching community which uses encrypted headers was found"?
This error message means that the supernode is not able to identify a packet as unencrypted. It does check for a sane packet format. If it fails the header is assumed encrypted (thus, "_seemingly_ encrypted header") and the supernode tries all communities that would make a key (some have already been ruled out as they definitely are unenecrypted). If no matching community is found, the error occurs.
If all edges use the same `-H` setting (all edges either with it or without it) and restarting the supernode does not help, most probably one of the components (an edge or the supernode) is outdated, i.e. uses a different packet format from time to time, a lot of changes happen to the packet format in a very short period of time, especially in _dev_ branch.
So, please make sure that all edges **and** the supernode have the exact same built version, e.g. all from current _dev_.
## Edge
### How can I know if peer-to-peer connection has successfully been established?
The edge also offers a local udp management port at which it provides some information about connected _peers_ allowing a peer-to-peer connection, and _pending peers_ whose connections are forwarded through the supernode.
The edge's management port defaults to 5644 and can be changed using edge's `-t` command line option. Connecting using the following command (localhost only)
`netcat -u localhost 5644`
answers every new line, i.e. pressing [ENTER] key, with current information. The edge even understands some simple commands, try `help`.
### The edge repeatedly throws an "Authentication error. MAC or IP address already in use or not released yet by supernode" message. What is wrong?
The edge encountered n2n's protection against spoofing. It prevents that one edge's identity, MAC and IP address, can be impersonated by some other while the original one is still online, see some [details](Authentication.md). Mostly, there are two situations which can trigger this:
If you use a MAC or IP address that already is in use, just change those parameters.
If the edge prematurely has ended in a non-regular way, i.e. by killing it using `kill -9 ...` or `kill -SIGKILL ...`, it did not have a chance to un-register with the supernode which still counts the edge for online. A re-registration with the same MAC or IP address will be unsuccessful then. After two minutes or so the supernode will have forgotten. A new registration with the same parameters will be possible then. So, either wait two minutes or chose different parameters to restart with.
And, as a matter of principal, always end an edge by either pressing `CTRL` + `C` or by sending SIGTERM or SIGINT by using `kill -SIGTERM ...` or `kill -SIGINT ...`! A plain `kill ...` without `-9` will do, too. And finally, a `stop` command to the management port peacefully ends the edge as well.

41
doc/Federation.md Normal file
View file

@ -0,0 +1,41 @@
# Supernode Federation
## Idea
To enhance resilience in terms of backup and fail-over, also for load-balancing, multiple supernodes can easily interconnect and form a special community, called **federation**.
## Using Multiple Supernodes
### Form a Federation
To form a federation, multiple supernodes need to be aware of each other. To get them connected, an additional `-l` option from command line is required at the supernode.
This option takes the IP address (or name) and the UDP port of another known supernode, e.g. `-l 192.168.1.1:1234`.
### Use a Federation
Federated supernodes take care of propagating their knowledge about other supernodes to all other supernodes and the edges.
So, in the first place, edges only need to connect to one supernode (called anchor supernode) using `-l` option. This supernode needs to be present at start-up.
Optionally, more anchor supernodes of the same federation can be provided to an edge using several `-l` options. This will counter scenarios with reduced assured initial supernode availability.
## How It Works
Supernodes should be able to communicate among each other as regular edges already do. For this purpose, a special community called federation was introduced. The federation feature provides some mechanisms to inter-connect the supernodes of the network enhancing backup, fail-over and load-sharing, without any visible behavioral change.
The default name for the federation is `*Federation`. Internally, a mandatory special character is prepended to the name: that way, an edge won't be able to provide a regular community with the same name of the federation. Optionally, a user can choose a federation name (same on all supernodes) and provide it via `-F mySecretFed` option to the supernode. Alternatively, the federation name can be passed through the environment variable `N2N_FEDERATION`.
Federated supernodes register to each other using REGISTER_SUPER message type. The answer, REGISTER_SUPER_ACK, contains a payload with information about other supernodes in the network.
This specific mechanism is also used during the registration process taking place between edges and supernodes, so edges are able to learn about other supernodes.
Once edges have received this information, it is up to them choosing the supernode they want to connect to. Each edge pings supernodes from time to time and receives information about them inside the answer. We decided to implement a work-load based selection strategy because it is more in line with the idea of keeping the workload low on supernodes. Moreover, this way, the entire network load is evenly distributed among all available supernodes.
An edge connects to the supernode with the lowest work-load and it is re-considered from time to time, with each re-registration. We use a stickyness factor to avoid too much jumping between supernodes.
Thanks to this feature, n2n is now able to handle security attacks such as DoS against supernodes and it can redistribute the entire load of the network in a fair manner between all the supernodes.
To serve scenarios in which an edge is supposed to select the supernode by round trip time, i.e. choosing the "closest" one, the `--select-rtt` command line option is available at the edge. Note, that workload distribution among supernodes might not be so fair then.
Furthermore, `--select-mac` would switch to a MAC address based selection strategy choosing the supernode active with the lowest MAC address.

262
doc/Hacking.md Normal file
View file

@ -0,0 +1,262 @@
# Hacking
--------
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/>](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.
For example, an asymmetric NAT would keep the mapping:
`<UDP,ExtPort> -> <IntIP, IntPort>`
and would redirect all the packets on external port ExtPort to the internal host
regardless of the remote IP.
Whereas a symmetric NAT would keep the mapping:
`<UDP,RemoteIP,ExtPort> -> <IntIP, IntPort>`
so only RemoteIP can send packets to the internal host. RemoteIP is the supernode
IP in case of n2n, to which the internal host has registered.
In n2n, P2P can work monodirectionally if only one of the two peers is behind a symmetric
NAT. For example, if A is behind symmetric NAT and B is behind asymmetric NAT
- A->B packets are P2P (will have the B public IP as destination)
- B->A packets must go through the supernode
If both the peers are behind symmetric NAT, then no P2P communication is possible.
## 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 section on 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 (allocating a new public socket
for the new outbound UDP "connection").
## Edge Resgitration 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 parameter;
(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 3
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=3 ! TTL ! Flags !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 ! Community :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 ! ... Community ... :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 ! ... Community ... !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24 ! Source MAC Address :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28 : ! Destination MAC Address :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 : !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 ! Socket Flags (v=IPv4) ! Destination UDP Port !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 ! Destination IPv4 Address !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 ! Compress'n ID ! Transform ID !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 ! Payload
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
So each n2n PACKET has a 48 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:
```
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 ! Socket Flags (v=IPv6) ! Destination UDP Port !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 ! Destination IPv6 Address :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 : :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 : :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 : !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 ! Compress'n ID ! Transform ID !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 ! Encapsulated ethernet payload
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```
-------
(C) 2008-2010 - Richard Andrews
January 2010 - Richard Andrews <andrews@ntop.org>

242
doc/ManagementAPI.md Normal file
View file

@ -0,0 +1,242 @@
# Management API
This document is focused on the machine readable API interfaces.
Both the edge and the supernode provide a management interface UDP port.
These interfaces have some documentation on their non machine readable
commands in the respective daemon man pages.
Default Ports:
- UDP/5644 - edge
- UDP/5645 - supernode
A Quick start example query:
`echo r 1 help | nc -w1 -u 127.0.0.1 5644`
## JSON Query interface
A machine readable API is available for both the edge and supernode. It
takes a simple text request and replies with JSON formatted data.
The request is in simple text so that the daemon does not need to include any
complex parser.
The replies are all in JSON so that the data is fully machine readable and
the schema can be updated as needed - the burden is entirely on the client
to handle different replies with different fields. It is expected that
any client software will be written in higher level programming languages
where this flexibility is easy to provide.
Since the API is over UDP, the replies are structured so that each part of
the reply is clearly tagged as belonging to one request and there is a
clear begin and end marker for the reply. This is expected to support the
future possibilities of pipelined and overlapping transactions as well as
pub/sub asynchronous event channels.
The replies will also handle some small amount of re-ordering of the
packets, but that is not an specific goal of the protocol.
Note that this API will reply with a relatively large number of UDP packets
and that it is not intended for high frequency or high volume data transfer.
It was written to use a low amount of memory and to support incremental
generation of the reply data.
With a small amount of effort, the API is intended to be human readable,
but this is intended for debugging.
## Request API
The request is a single UDP packet containing one line of text with at least
three space separated fields. Any text after the third field is available for
the API method to use for additional parameters
Fields:
- Message Type
- Options
- Method
- Optional Additional Parameters
The maximum length of the entire line of text is 80 octets.
All request packets should generate a reply. However, this reply may simply
be an error.
### Message Type
This is a single octet specifying the type:
- "r" for a read-only method (or one that does not need change permissions)
- "w" for a write method (or one that makes changes)
- "s" for a subscribe method to request this socket receive some events
To simplify the interface, the reply from both read and write calls to the
same method is expected to contain the same data. In the case of a write
call, the reply will contain the new state after making the requested change.
The subscribe and events message flow works with a different set of messages.
### Options
The options field is a colon separated set of options for this request. Only
the first subfield (the "tag") is mandatory. The second subfield is a set
of flags that describe which optional subfields are present.
If there are no additional subfields then the flags can be omitted.
SubFields:
- Message Tag
- Optional Message Flags (defaults to 0)
- Optional Authentication Key
#### Message Tag
Each request provides a tag value. Any non error reply associated with this
request will include this tag value, allowing all related messages to be
collected within the client. The tag will be truncated if needed by the
daemon, but there will be at least 8 octets of space available.
Where possible, the error replies will also include this tag, however some
errors occur before the tag is parsed.
The tag is not interpreted by the daemon, it is simply echoed back in all
the replies. It is expected to be a short string that the client knows
will be unique amongst all recent, still outstanding or subscription requests
on a given socket.
One possible client implementation is a number between 0 and 999, incremented
for each request and wrapping around to zero when it is greater than 999.
#### Message Flags
This subfield is a set of bit flags that are hex-encoded and describe any
remaining optional subfields.
Currently, only one flag is defined. The presence of that flag indicates
that an authentication key subfield is also present.
Values:
- 0 - No additional subfields are present
- 1 - One additional field, containing the authentication key
#### Authentication Key
A simple string password that is provided by the client to authenticate
this request. See the Authentication section below for more discussion.
#### Example Options value
e.g:
`102:1:PassWord`
### Example Request string
e.g:
`r 103:1:PassWord peer`
## Reply API
Each UDP packet in the reply is a complete and valid JSON dictionary
containing a fragment of information related to the entire reply.
Reply packets are generated both in response to requests and whenever
an event is published to a subscribed channel.
### Common metadata
There are two keys in each dictionary containing metadata. First
is the `_tag`, containing the Message Tag from the original request.
Second is the `_type` which identifies the expected contents of this
packet.
### `_type: error`
If an error condition occurs, a packet with a `error` key describing
the error will be sent. This usually also indicates that there will
be no more substantial data arriving related to this request.
e.g:
`{"_tag":"107","_type":"error","error":"badauth"}`
### `_type: begin`
Before the start of any substantial data packets, a `begin` packet is
sent. For consistency checking, the method in the request is echoed
back in the `error` key.
e.g:
`{"_tag":"108","_type":"begin","cmd":"peer"}`
For simplicity in decoding, if a `begin` packet is sent, all attempts
are made to ensure that a final `end` packet is also sent.
### `_type: end`
After the last substantial data packet, a final `end` packet is sent
to signal to the client that this reply is finished.
e.g:
`{"_tag":"108","_type":"end"}`
### `_type: row`
The substantial bulk of the data in the reply is contained within one or
more `row` packets. The non metadata contents of each `row` packet is
defined entirely by the method called and may change from version to version.
Each `row` packet contains exactly one complete JSON object. The row replies
may be processed incrementally as each row arrives and no batching of multiple
packets will be required.
e.g:
`{"_tag":"108","_type":"row","mode":"p2p","ip4addr":"10.135.98.84","macaddr":"86:56:21:E4:AA:39","sockaddr":"192.168.7.191:41701","desc":"client4","lastseen":1584682200}`
### `_type: subscribed`
Signals that the subscription request has been successfully completed.
Any future events on the requested channel will be asynchronously sent
as `event` packets using the same tag as the subscribe request.
### `_type: unsubscribed`
Only one management client can be subscribed to any given event topic, so if
another subscribe request arrives, the older client will be sent this message
to let them know that they have been replaced.
(In the future, this may also be sent as a reply to a explicit unsubscribe
request)
### `_type: replacing`
If a new subscription request will replace an existing one, this message is
sent to the new client to inform them that they have replaced an older
connection.
### `_type: event`
Asynchronous events will arrive with this message type, using the same tag as
the original subscribe request. Just like with the `row` packets, the non
metadata contents are entirely defined by the topic and the specific n2n
version.
## Subscribe API
A client can subscribe to events using a request with the type of "s".
Once a subscribe has been successfully completed, any events published
on that channel will be forwarded to the client.
Only one management client can be subscribed to any given event topic,
with newer subscriptions replacing older ones.
The special channel "debug" will receive copies of all events published.
Note that this is for debugging of events and the packets may not have
the same tag as the debug subscription.
## Authentication
Some API requests will make global changes to the running daemon and may
affect the availability of the n2n networking. Therefore the machine
readable API include an authentication component.
Currently, the only authentication is a simple password that the client
must provide. It defaults to 'n2n' and can manually be set through the
command line parameter `--management-password <pw>` for edge as well
as for supernode.

188
doc/Routing.md Normal file
View file

@ -0,0 +1,188 @@
# IPv4 Routing (Linux)
## General Remarks
Reaching a remote network or tunneling all the internet traffic via n2n are two common tasks which require a proper routing setup. n2n supports routing needs providing options for packet forwarding including broadcasts as well as modifying the routing table.
In this context, the `server` is the edge node which provides access to the remote network/internet, whereas the `client` is the connecting edge node.
In order to enable routing, the `server` must be configured as follows:
1. Add the `-r` option to the edge options to enable routing
2. Enable packet forwarding with `sudo sysctl -w net.ipv4.ip_forward=1`
3. Enable IP masquerading: `sudo iptables -t nat -A POSTROUTING -j MASQUERADE`
On the client side, the easiest way to configure routing is via the `-n` option. For example:
- In order to connect to the remote network `192.168.100.0/24`, use `-n 192.168.100.0/24:10.0.0.1`
- In order to tunnel all the internet traffic, use `-n 0.0.0.0/0:10.0.0.1`
10.0.0.1 is the IP address of the gateway to use to route the specified network. It should correspond to the IP address of the `server` within n2n. Multiple `-n` options can be specified.
As an alternative to the `-n` option, the `ip route` linux command can be manually used. See the [n2n-gateway.sh](scripts/n2n-gateway.sh) script for an example. See also the following description of other use cases and in depth explanation.
## Special Scenarios
### Assumptions
- There are two Local Area Networks, namely 10.11.12.0/24 (maybe at
**h**ome) and 192.168.1.0/24 (maybe in **o**ffice).
- These networks are connected to the internet via routers 10.11.12.1
and 192.168.1.1, respectively.
- In each network, there is a computer running a successfully setup n2n
node: 10.11.12.5 (**h**ickory) and 192.168.1.6 (**o**scar). They are
connected to their networks through a device called _eth0_. Their n2n
devices shall be called _n2n0_, and their n2n IP addresses are
10.99.99.50 (**h**ickory) and 10.99.99.60 (**o**scar) in the
10.99.99.0/24 network.
- The _iptables_ are flushed.
### Prerequisites
- Both, **h**ickory and **o**scar have ip forwarding enabled: `echo 1 > /proc/sys/net/ipv4/ip_forward` or `sysctl -w net.ipv4.ip_forward=1`. To
make this setting persistent over reboot, a file containing the line
`net.ipv4.ip_forward=1` could be added in /etc/sysctl.d/ your distro
may vary.
- To allow n2n to forward packets, both edge nodes need to be started
with `-r` option on their command line. All other regular network
interfaces usually already allow packet forwarding and thus do not need
any further configuration.
### Reach Complete Office Network from n2n Node at Home
- To make **h**ickory send all packets with office destination via
**o**scar, **h**ickory needs to be made aware of where to route this
packets to. On **h**ickory: `ip route add 192.168.1.0/24 via 10.99.99.60 dev n2n0 src 10.11.12.5`.
- **o**scar needs to know where to send packets to, too. So, on
**o**scar: `ip route add 10.11.12.5 via 10.99.99.50 dev n2n0 src 192.168.1.6`.
**o**scar and **h**ickory should now be able to exchange packets by
using just their regular (non-n2n) IP addresses 10.11.12.5 and 192.168.1.6.
To make the complete office network aware of how packets or answers are
sent to **h**ickory, one more step is required:
- Packets from any office computer to **h**ickory need to be directed to
**o**scar that thanks to enabled IP forwarding and the routing rule
already knows how to handle this kind of packets.
- To handle it in a one-stop-shop, the office router 192.168.1.1 can
be configured to direct those packets to **o**scar. Luckily, even most
modern small-office-and-home routers allow to add static routing rules
via a web interface. A rule like "All packets for host 10.11.12.5 (or
network 10.11.12.0/24) need to be sent to another router, namely
192.168.1.5" will do. This is the **recommended** solution.
- However, a **less recommended** but working option would be to add
static routes to each single of those computers in the office network
that shall be able to connect to or be accessed by **h**ickory. On
those, e.g. **o**livia with IP address 192.168.1.123: `ip route add 10.11.12.5 via 192.168.1.5 dev eth0 src 192.168.1.123`.
- Alternatively, in case the office router does not allow to have
added own static routing rules, **o**scar needs to perform NAT for all
connections initiated from **h**ickory:
`iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE`
`iptables -A FORWARD -i eth0 -o n2n0 -m state --state RELATED,ESTABLISHED -j ACCEPT`
`iptables -A FORWARD -i n2n0 -o eth0 -j ACCEPT`
There is a major drawback with this solution which thus is the **least
recommended**: Connections between **h**ickory and the office network
will only work if initiated by **h**ickory not the other way 'round.
By the way, in case _iptables_ are messed up, they can be flushed by:
`iptables -F`
`iptables -X`
`iptables -t nat -F`
`iptables -t nat -X`
`iptables -t mangle -F`
`iptables -t mangle -X`
`iptables -t raw -F`
`iptables -t raw -X`
`iptables -t security -F`
`iptables -t security -X`
`iptables -P INPUT ACCEPT`
`iptables -P FORWARD ACCEPT`
`iptables -P OUTPUT ACCEPT`
### Reach n2n Node in Office from Whole Home Network
This is easy:
- Just exchange home and office IP addresses and the computer names in
the instructions given above.
### Reach Whole Home Network from Whole Office Network
This is not too complicated either. Basically, follow the given example
above and apply the following changes:
- The instructions used above need to be expanded from **h**ickory's IP
10.11.12.5 to its full network 10.11.12.0/24 in the route commands on
**o**scar:, especially: `ip route add 10.11.12.0/24 via 10.99.99.50 dev n2n0 src 192.168.1.6`.
- In case of adding a static route to the office network router
192.168.1.1, the home network 10.11.12.0/24 must be specified instead of
**h**ickory's more specific IP address 11.11.12.5. Same for the less
recommended static routes on other office computers.
- Packets from home network's computers to the office network need to be
sent through the n2n tunnel. The three alternatives given above can be
used just with exchanged office and home IP addresses. One needs to be
aware that NAT only (third alternative) on both sides will not allow any
connection, i.e. at least on one side static routes need to be added
either to the router (best option) or all those computers that shall be
able to connect to the other network.
### Route All Internet Traffic from n2n Node at Home through Office Network
This scenario could be considered a n2n-tunneled VPN connection which
also would work for travelling users on their laptop. All external
internet traffic will appear to originate from **o**scar and the office
network.
- First, one of the setups described above needs to be in place, with
the following change:
- NAT on **o**scar (see the three _iptables_ commands above) must be
enabled. It will not work without because the office router 192.168.1.1
usually denies forwarding to packets not originating from its own
network. It could be in addition to the eventually installed static
routes for 10.11.12.0/24 in the router 192.168.1.1 or on other office
computers it will not interfere. However, **o**scar definitely needs
the route given above: `ip route add 10.11.12.5 via 10.99.99.50 dev n2n0 src 192.168.1.6`.
- To have **h**ickory's complete internet traffic going through the n2n
tunnel, its default route needs to be changed:
`ip route del default`
`ip route add default via 10.99.99.60 dev n2n0 src 10.11.12.5`
- **h**ickory's home network should still be reachable as usually,
_eth0_ and the associated network 10.11.12.0/24 get their very own
route. If not, i.e. it was only covered by default route before, it
needs to be added: `ip route add 10.11.12.0/24 dev eth0 src 10.11.12.5`.
- Unfortunately (unless the supernode is on **h**ickory's local
network), n2n supernode becomes unreachable for **h**ickory. To fix it:
`ip route add <supernode IP address> via 10.11.12.1 dev eth0 src 10.11.12.5`
The supernode's IP address needs to be known to have this work. However,
if the supernode's IP needs to be resolved from some domain name (FQDN),
e.g. in case of using dynamic domain name services, a DNS server needs
to remain reachable, too. Either the reachable home network router
10.11.12.1 is good enough for that (if it offers DNS) or another route
could to be added and **h**ickory's DNS settings might be set
accordingly, maybe to Google's 8.8.8.8.
If [DNS leaks](https://en.wikipedia.org/wiki/DNS_leak) do not matter,
this setup is complete.
### Preventing DNS Leaks
Otherwise, there is more to it: Without changes, all future DNS queries
go through the home router 10.11.12.1 to the ISP's servers or directly
to Google (via the home router 10.11.12.1 along the configured route for
8.8.8.8 and not through the n2n tunnel) while the remaining traffic
ships through the n2n tunnel.
To prevent such a DNS leak, the supernode's IP address must be
determined independently from **h**ickory's DNS configuration, e.g. by
digesting `dig +short mysupernode.myfavoritednsservice.com @8.8.8.8`'s
output in the n2n-edge's setup script for both, the edge node command
line as well as the static route mentioned above. Without further
additional work, dynamic address changes remain undetected. A static
route to 8.8.8.8 is still required. **h**ickory's regular DNS
configuration should query a different DNS server for its regular DNS
needs, e.g. 9.9.9.9 or 1.1.1.1 or maybe the office DNS server, maybe
192.168.1.1. This guarantees the regular DNS queries also to get sent
through the n2n tunnel.
A test for DNS leaks can be found [here](https://www.dnsleaktest.com/).

61
doc/Scratchpad.md Normal file
View file

@ -0,0 +1,61 @@
# n2n's Scratchpad
## RPM Packaging
```
bash
./autogen.sh
./configure
make
cd packages/rpm
./configure
rpmbuild -bb ./n2n.spec
```
## New Features between 2.0.x and 2.1.x
- Better ming Windows build support.
- Added `-E` flag to allow multicast ethernet traffic.
## Draft changelog between 2.8 and 3.0 (as of September 27, 2021)
### New Features
- Federated supernodes to allow multiple supernodes for load balancing and fail-over (`doc/Federation.md`)
- Automatic IP address assignment allows edges to draw IP addresses from the supernode (just skip `-a`)
- Allowed community names can be restricted by regular expressions (`community.list` file)
- Network filter for rules (`-R`) allowing and denying specific traffic to tunnel
- Experimental TCP support (`-S2`) lets edges connect to the supernodes via TCP in case firewalls block UDP (not available on Windows yet)
- All four supported ciphers offer integrated versions rendering OpenSSL dependency non-mandatory (optionally still available)
- MAC and IP address spoofing prevention
- Network interface metric can be set by command-line option `-x` (Windows only)
- Re-enabled local peer detection by multicast on Windows
- Edge identifier (`-I`) helps to identify edges more easily in management port output
- Optionally bind edge to one local IP address only (extension to `-p`)
- A preferred local socket can be advertised to other edges for better local peer-to-peer connections (`-e`)
- Optional edge user and password authentication (`-J`, `-P`, `doc/Authentication.md`)
- Optional json format at management port allows for machine-driven handling such as `.html` page generation (`scripts/n2n-httpd`) or script-based evaluation (`scripts/n2n-ctl`)
- Completely overhauled build system including GitHub's action runners performing code syntax and formal checks, creating and running test builds, providing binairies and packages as artifacts and running verification tests
### Improvements
- Increased edges' resilience to temporary supernode failure
- Fixed a compression-related memory leak
- Ciphers partly come with platform-specific hardware acceleration
- Added a test framework (`tools/test-*.c` and `tests/`)
- Clean-up management port output
- Polished benchmark tool output
- Spun-off the name resolution into a separate thread avoiding lags
- Added support for additional environment variables (`N2N_COMMUNITY`, `N2N_PASSWORD`, and `N2N_FEDERATION`)
- Implemented new `reload_communities` command to make supernode hot-reload the `-c` provided `community.list` file, issued through management port
- Reactivated send out of gratuitous ARP packet on establishing connection
- Enhanced documentation (`doc/` folder) including the man pages and command-line help text (`-h` and more detailed `--help`)
- Self-monitoring time stamp accuracy for use on systems with less accurate clocks
- Fixed man pages' and config files' paths
- Code clean-up

117
doc/Scripts.md Normal file
View file

@ -0,0 +1,117 @@
# Scripts
There are a number of useful scripts included with the distribution.
Some of these scripts are only useful during build and development, but
other scripts are intended for end users to be able to use. These scripts
may be installed with n2n as part of your operating system package.
All scripts can be found in the `scripts` directory.
Short descriptions of these scripts are below.
## End user scripts
### `n2n-ctl`
This python script provides an easy command line interface to the running
n2n processes. It uses UDP communications to talk to the Management API.
By specifying the right UDP port, it can talk to both the edge and the
supernode daemons.
Example:
- `scripts/n2n-ctl --help`
- `scripts/n2n-ctl help`
### `n2n-httpd`
This python script is a simple http gateway to the running edge. It provides
a proxy for REST-like HTTP requests to talk to the Management API.
By default it runs on port 8080.
It also provides a simple HTML page showing some edge information, which when
run with default settings can be seen at http://localhost:8080/ (Also
a http://localhost:8080/supernode.html page for the supernode)
Example:
- `scripts/n2n-httpd --help`
- `scripts/n2n-httpd 8087`
## Build and Development scripts
### `hack_fakeautoconf.sh`
This shell script is used during development to help build on Windows
systems. An example of how to use it is shown in
the [Building document](Building.md)
### `indent.sh`
This shell script is a wrapper for the `uncrustify` C code style checker
which checks or applies a set of rules to the code. It is used during
the automated lint checks.
### `n2n-gateway.sh`
A sample script to route all the host traffic towards a remote gateway,
which is reachable via the n2n virtual interface.
### `version.sh`
This script is used to determine the current version number during the
build process.
It looks at both the VERSION file and the GIT tags and outputs the
version number to use.
## Monitoring and statistics
### `munin/n2n_`
This is a simple monitoring script that can be used with the munin-node
system to monitor the n2n daemons.
This is a fully autoconfigurable wildcard munin plugin, but to get a quick
sample:
get a list of suggested plugin names:
```
munin/n2n_ suggest
```
Enable some of those names:
```
ln -s /usr/share/munin/plugins/n2n_ /etc/munin/plugins/n2n_supernode_pkts
ln -s /usr/share/munin/plugins/n2n_ /etc/munin/plugins/n2n_supernode_counts
```
Manually test fetching and config:
```
/etc/munin/plugins/n2n_supernode_pkts
/etc/munin/plugins/n2n_supernode_pkts config
```
## Testing scripts
### `test_harness.sh`
This shell script is used to run automated tests during development. It is
run with a testlist filename - pointing at a file containing the list of
tests to run.
Each test needs a file containing the expected output `${TESTNAME}.expected`
which is expected to exist in the same directory as the testlist (this dir is
referred to as `${listdir}` below).
Each test is a program, searched for in several locations, including the
`${listdir}/../scripts` dir.
Each test is run with its output being sent to `*.out` files in the `listdir`
and compared with the expected output.
### `scripts/test_integration_supernode.sh`
This starts a supernode and runs an integration test on the Json API using
the `n2n-ctl` command.

151
doc/TapConfiguration.md Normal file
View file

@ -0,0 +1,151 @@
# TAP Device Configuration
n2n provides its service through a TAP device which is the virtual ethernet device seen by the computer and user. As a prerequisite, it requires the appropriate TAP driver to be installed. Most Linux systems come with it. If not loaded, `sudo modprobe tap` will do.
For MacOS and Windows there are specific instructions; please see the [Building](./Building.md) document.
## Device Name
If the OS specific driver allows **naming** the virtual Ethernet device created by n2n, the `-d <device>` command-line option can be used to give a name, e.g. `-d n2n0`. This device name makes the virtual ethernet device easily accessible to all `ip` command activity, `iptables`, `tcpdump` and any other of your preferred network tools. It defaults to `edge0` if not provided through `-d`.
One exception applies to Windows: As the installed TAP driver(s) come with fixed names, `-d <device>` **selects** the appropriate device by name out of the present ones. This is only required if more than one TAP devices are present. To help with it, `edge --help` lists the available TAP adapters at the bottom of its output (Windows only).
## MAC
Even virtual ethernet devices have a MAC address. As in real networks, it should be unique as it is used to identify the different participants and transport packets accordingly. The MAC address can optionally be specified by using the `-m <MAC address>` command line parameter, e.g. `-m 01:02:03:04:05:06`. If omitted, n2n tries to assign a random MAC address.
## IP Address
n2n supports several ways to assign an IPv4 address to the virtual ethernet device. Support for IPv6 addresses relies on OS support.
### Manually Assigned IP Address
The command line parameter `-a <static:IP address>` assigns a static IP address, e.g. `-a static:192.168.8.5` to the device. The optional `static` keyword (and the delimiting colon) can be omitted, so `-a 192.168.8.5` works as well.
The netmask in CIDR notation can optionally be appended to the address, e.g. `-a 192.168.8.5/24` for netmask `255.255.255.0` which also is the default should the netmask not be provided.
### Auto IP Address
If `-a` is omitted, the supernode assigns an IP address to the node. This feature uses different IP address pools on a per-community basis. So, all edges of the same community will find themselves in the same sub-network.
By default, `/24`-sized IP address sub-network pools from the upper half of the `10.0.0.0` class A network will be used, that is from `10.128.0.0/24``10.255.255.0/24`. The supernode can be configured to assign addresses from a different network range: `-a 10.0.0.0-10.255.0.0/16` would the supernode make use of the complete `10.0.0.0` class A range but handle `/16`-sized sub-networks. Also, named communities could be pre-assigned certain sub-networks, please see the explanatory comments in the `community.list` file.
### DHCP
If an edge of the community runs a DHCP server, the others could draw their IP addresses from there. It requires the new edges to start-up with the `-r -a dhcp:0.0.0.0` parameters (literally). More details can be found [at this discussion](https://github.com/ntop/n2n/issues/629).
### IPv6
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.
For example, 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` allows you to bring up a TAP interface and configure addressing
prior to starting the edge. It also allows the edge to be restarted without the
interface closing (which would normally affect routing tables).
Once the IPv6 addresses are configured and edge is started, IPv6 neighbor discovery
packets flow (get broadcast) and IPv6 entities self-arrange. Test your IPv6
setup with `ping6` - the IPv6 ping command.
## MTU
The MTU of the VPN interface is set to a lower value (rather than the standard
value of 1500 bytes) to avoid excessive fragmentation of the datagram sent over the internet.
This is required because n2n adds additional headers to the packets received from
the VPN interface. The size of the final frame sent through the internet interface
must have a size lower or equal to the internet interface MTU (usually 1500 bytes).
As a fragmentation example, suppose that a 3000 byte TCP segment should be sent through
the VPN. If the VPN interface MTU is set to 1500, the packet will be split into two
fragments of 1500 bytes each. However, n2n will add its headers to each fragment, so
each fragment becomes a 1540 byte packet. The internet interface MTU of 1500 bytes
will fragment each packet again in two further fragments, e.g. 1500 + 50 bytes, so a
total of 4 fragments will be sent over the internet. On the other hand, if the VPN interface
MTU was set to 1460 bytes, it would result in only 3 fragments sent as the initial segment of
3000 bytes would be split in 1460 + 1460 + 80 bytes without further fragmentation.
IP packet fragmentation in general is something to avoid, as described in
http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-87-3.pdf. If possible,
the fragmentation should be moved to the TCP layer by a proper MSS value.
This can be forced by mangling the packet MSS, which is called "MSS clamping" (currently not
implemented in n2n). See https://github.com/gsliepen/tinc/blob/228a03aaa707a5fcced9dd5148a4bdb7e5ef025b/src/route.c#L386.
The exact value to use as a clamp value, however, depends on the PMTU, which is the minimum
MTU of the path between two hosts. Knowing the PMTU is also useful for a sender in order to
avoid fragmentation at IP level. Trying to find the highest non-fragmenting MTU possible is useful since it allows to
maximize bandwidth.
### PMTU Discovery Failures
Most operating systems try to periodically discover the PMTU by using a PMTU discovery algorithm.
This involves setting the DF (don't fragment) flag on the IP packets. When a large IP packet exceeds
the MTU of a router in the path, an "ICMP Fragmentation Needed" message should be received, which will
help the OS along to tune the size of the next IP packets. However, some routers do not report such ICMP message,
which results in packets being silently dropped. The `tracepath` tool can be used to detect the PMTU.
The main problem with this situation is that the actual PMTU is unknown, so an automatic
solution is not applicable. The user must manually specify a lower MTU for the VPN interface
in order to solve the issue.
### n2n and MTU
n2n shall work by default in different environments. For this reason, the following solution
has been provided:
- PMTU discovery is disabled if possible (via the IP_MTU_DISCOVER socket option). This avoids
silently dropping an oversized packet due to the DF flag; however, it possibly increments fragmentation on the path.
- As explained above, a lower MTU is set on the VPN interface, thus removing excessive fragmentation on
the sender.
- A value of 1290 bytes is used instead of 1500 bytes as reference value for the internet interface MTU.
This essentially avoids fragmentation if the PMTU is greater or equal than 1400 bytes.
This is a conservative solution which should make n2n work by default. The user can manually
specify the MTU (`-M <mtu>`) and re-enable PMTU discovery (`-D`) via the command-line interface options.
## Interface Metric and Broadcasts
On Windows, broadcasts are sent out to the network interface with the lowest metric only. This usually is the
WAN interface with its default metric of `25`. The `-x <metric>` option could be used to configure the TAP with a
lower interface metric and hence facilitate service and online game server detection over n2n.
Linux and others do not require this feature as broadcasts are sent to all network interfaces by default, also to the
virtual ones.
## Multicast
n2n does not transmit multicast packets by default. It can be enabled by edge's `-E` command-line parameter.
## Egde Description
To keep edge's and supernode's management port output well arranged and understandable, each edge can have a plain text description
fed to the edge by the optional `-I <edge description>` command-line parameter. If not provided, n2n uses the
hostname by default.
A description field's hash value is used to choose an auto IP address. So, just be aware that changing the hostname
can lead to assigning a different auto IP address on next edge start-up if auto IP address is used.
## Routing
n2n supports routing the traffic through its network. `-r` enables an edge to accept packets at its TAP interface not originating from the local IP address or not destined to the local IP address. As there is more to routing than just this one command-line option, please refer to the dedicated [Routing](Routing.md) document
explaining it all in detail.
## Traffic Filter
Setting up the integrated traffic filter permits to define exactly the kind of allowed traffic or deny
other on edge's TAP interface. It helps to keep unwanted traffic out of the n2n network for
bandwidth and security reasons. The traffic filter is disabled by default and gets activated by providing
as many `-R <rule>`-rules as required through edge's command-line. Specifics are written down in the
[Traffic Restrictions](TrafficRestricitons.md) documentation.

View file

@ -0,0 +1,41 @@
# Traffic Restrictions
It is possible to drop or accept specific packet transmit over edge network interface by rules. Rules can be specify by (`-R rule_str`) multiple times.
## Rule String Format
rule_str format: `src_ip/len:[b_port,e_port],dst_ip/len:[s_port,e_port],TCP+/-,UDP+/-,ICMP+/-`
`ip/len` indicate a cidr block, len can be ignore, means single ip (not cidr block) will be use in filter rule.
`+`,`-` after `TCP`,`UDP`,`ICMP` proto type indicate allow or drop packet of that proto. if any of above three proto missed, the rule will not take effect for that proto.
Ports range `[s_port,e_port]` can be instead by single port number. If not specify, `[0,65535]` will be used. Ports range include start_port and end_port.
examples:
`192.168.1.5/32:[0,65535],192.168.0.0/24:[8081,65535],TCP-,UDP-,ICMP+`
`192.168.1.5:[0,65535],192.168.0.0/24:8000,ICMP+`
`192.168.1.5,192.168.0.7,TCP-,UDP-,ICMP-` // packets by all proto of all ports from 192.158.1.5 to any ports of 192.168.0.7 will be dropped.
## Multiple Rules
`-R rule_str` can be used multiple times to add multiple rules. Each `-R rule_str` add one rule. for example:
`edge -c xxxx -k xxxx -a 192.168.100.5 -l xxx.xxx.xxx.xxx:1234 -r -R 192.168.1.5/32:[0,65535],192.168.0.0/24:[8081,65535],TCP-,UDP-,ICMP+ -R 192.168.1.5:[0,65535],192.168.0.0/24:8000,ICMP+ -R 192.168.1.5,192.168.0.7,TCP-`
## Matching Rules Priority
If multiple rules matching packet's ips and ports, the rule with smaller cidr block(smaller address space) will be selected. That means rules with larger `len` value has higher priority.
Actually, current implementation will add the `len` of src cidr and dst cidr of each matched rules as priority value, the rule with largest priority value will take effect.
## Blocklist/Allowlist mode
Packets that cannot match any rule will be accepted by default. Users can add rules to block traffics.
This behavior can be change by add the rule : `0.0.0.0/0:[0,65535],0.0.0.0/0:[0,65535],TCP-,UDP-,ICMP-`. Then all traffic will be dropped, users need add rules to allow traffics.
for example, `-R 0.0.0.0/0,0.0.0.0/0,TCP-,UDP-,ICMP- -R 192.168.100.0/24,192.168.100.0/24,ICMP+` dropped all traffic, except ICMP traffics inside `192.168.100.0/24`.
More complex behavior can be set with the feature of `Matching Rules Priority`.