Merge branch 'dev' into prepReg

This commit is contained in:
Luca Deri 2020-08-12 14:41:09 +02:00 committed by GitHub
commit d4e9df013e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 826 additions and 545 deletions

View File

@ -1,19 +1,89 @@
# Changelog
#### n2n 2.4 (August 2018)
## n2n 2.8 (August 2020)
This release brings significant new features to n2n's crypto world and offers
some compression opportunities. The added support for routing table manipulation
might increase comfort. Besides further honing existing features, this release
addresses some bugs.
### New Features
* Two lightweight stream ciphers: ChaCha20 (optional, through OpenSSL) & SPECK (integrated)
* Full Header Encryption (including packet checksumming as well as replay protection)
* A callback interface to better integrate n2n in third party software (you can still use it stand-alone)
* Enable the integrated LZO1x compression
* Add optional ZSTD compression (through zstdlib)
* Support for changing system routes at program start and end
* User and group id parameter for supernode
* Application of cryptography in n2n is seperately documented
* Add a new pseudo random number generator with higher periodicity seeded with more entropy if available
### Improvements
* Have AES and ChaCha20 use OpenSSL's `evp_*` interface to make better use of available hardware acceleration
* Fix invalid sendto when supernode name resolution fails
* Update to supernode's purge logic
* Extended management supernode's port output
* Fix read tap device failed when OS wakes up from sleep
* Free choice of supernode's management UDP port (for multiple supernodes on one machine)
* Additional trace messages to better indicate established connections and connection type
* Fix edge's register-to-supernode loop
* Remove redundant code
* Restructure the code in directories
* Clean-up platform-dependant code
* Compile fixes for Windows
* Fix build warnings
* …and many more under-the-hood fixes and tunings
## n2n 2.6 (March 2020)
The 2.6 release is mostly a maintenance release to address the issues
of 2.4 that has been the first release since a long time of silence.
### New Features
* AES encryption that features an overall speed bump (12x speed) and security with respect to Twofish used in the previous n2n version
* Add ability to specify a whitelist of allowed communities on the supernode
* Implement local peers discovery via multicast
* Full peer-to-peer topology support.
* Add support for multiple edge systemd services
* Add benchmark tool for the encryption throughput
* Implement packet stats for P2P vs supernode communication
* Automatically drop privileges to user n2n
* Add support for ARM64 build
* More options to control MTU, P2P connections, TOS and log verbosity
* Implement a wireshark dissector for the n2n protocol
* Implement n2n-decode utility to decode and dump traffic to PCAP
### Improvements
* Extensive Windows and OpenWRT support.
* Windows compilation fixes and instructions
* Instructions and makefile file to build n2n on OpenWRT
* MacOS compilation fixes and instructions
* Improve the connection stability and the chances to establish a P2P connection
* Stable and more resilient connection.
* Remove keyschedule support to simplify the encryption code
* Replace peers linked list with hash table for faster lookup in big networks
* Integrate the changes made in the meyerd fork of n2n
* Remove calls to system() in tuntap_linux and use netlink instead
* n2n version improvements
## n2n 2.4 (August 2018)
This is the first release after 2012 and thus it is focusing mainly
on making it work on current operating system versions, so that the
next release will be based on modern code
next release will be based on modern code.
## New features
### New Features
* Added deb/rpm packages
* Added systemd configuration files
* Added ability to read configuration files instead of using only the CLI (needed for packaging)
* Added n2n Android app
* Implemented simple API to embed n2n in applications (in addition to use it stand-alone)
## Improvements
### Improvements
* Major code cleanup
* Fixed compilation issues on MacOS
* Fixed Linux segmentation fault

View File

@ -2,7 +2,7 @@
# NOTE: update version in CMakeLists.txt after changing these
N2N_MAJOR="2"
N2N_MINOR="7"
N2N_MINOR="9"
N2N_PATCH="0"
N2N_VERSION_SHORT="$N2N_MAJOR.$N2N_MINOR.$N2N_PATCH"

View File

@ -6,3 +6,4 @@ Code contributions courtesy of:
* Lukasz Taczuk
* Alaric Snell-Pym <alaric@kitten-technologies.co.uk>
* Babak Farrokhi <babak@farrokhi.net> [FreeBSD port]
* Logan oos Even

View File

@ -6,7 +6,7 @@
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 CBC mode (`-A2`)
- Twofish in CTS mode (`-A2`)
- AES in CBC mode (`-A3`)
- ChaCha20 (CTR) (`-A4`)
- SPECK in CTR mode (`-A5`)
@ -17,12 +17,12 @@ The following chart might help to make a quick comparison and decide what cipher
| Cipher | Mode | Block Size | Key Size | IV length |Speed | Built-In | Origin |
| :---: | :---:| :---: | :---: | :---: |:---: | :---: | --- |
|Twofish | CBC | 128 bits | 256 bit | 32 bit | - | Y | Bruce Schneier |
|Twofish | CTS | 128 bits | 256 bit | 32 bit | - | Y | Bruce Schneier |
|AES | CBC | 128 bits | 128, 192, 256 bit| 64 bit | O..+ | N | Joan Daemen, Vincent Rijmen, NSA-approved |
|ChaCha20| CTR | Stream | 256 bit | 128 bit | +..++| N | Daniel J. Bernstein |
|SPECK | CTR | Stream | 256 bit | 128 bit | ++ | Y | NSA |
As the two block ciphers Twofish and AES are used in CBC mode, they require a padding which results in encrypted payload size modulo their blocksize. Sizewise, this could be considered as a disadvantage. On the other hand, stream ciphers need a longer initialization vector (IV) to be transmitted with the cipher.
The two block ciphers Twofish and AES are used in CTS mode (Twofish) and CBC mode(AES). AES requires a padding which results in encrypted payload size modulo their blocksize. Sizewise, this could be considered as a disadvantage. On the other hand, stream ciphers need a longer initialization vector (IV) to be transmitted with the cipher.
Note that AES and ChaCha20 are available only if n2n is compiled with openSSL support. n2n will work well without them offering the respectively reduced choice of remaining built-in ciphers (Twofish, SPECK).
@ -30,9 +30,7 @@ Note that AES and ChaCha20 are available only if n2n is compiled with openSSL su
This implementation prepends a 32 bit random value to the plain text. In the `src/transform_tf.c` file, it is called `nonce`. In CBC mode, this basically has the same effect as a respectively shorter IV.
Padding to the last block happens by filling `0x00`-bytes and indicating their number as the last byte of the block. This could lead to up to 16 extra bytes.
Other than that, it is plain Twofish in CBC mode.
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.
Twofish is the slowest of the ciphers present.
@ -42,7 +40,7 @@ _We might try to find a faster implementation._
AES uses the standard way of an IV but it does not neccessarily transmit the full IV along with the packets. The size of the transmitted part is adjustable by changing the `TRANSOP_AES_IV_SEED_SIZE` definition found in `src/transform_aes.c`. It defaults to 8 meaning that 8 bytes (of max 16) are transmitted. The remaining 8 bytes are fixed, key-derived material is used to fill up to full block size. A single AES-ECB encryption step is applied to these 16 bytes before they get used as regular IV for AES-CBCing the payload.
The padding scheme is the same as the one used with Twofish.
Padding to the last block happens by filling `0x00`-bytes and indicating their number as the last byte of the block. This could lead to up to 16 extra bytes.
AES relies on openSSL's `evp_*` interface 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.

View File

@ -36,8 +36,11 @@
/* Moved here to define _CRT_SECURE_NO_WARNINGS before all the including takes place */
#ifdef WIN32
#include "win32/n2n_win32.h"
#ifdef _MSC_VER
#include "config.h" /* Visual C++ */
#else
#include "win32/winconfig.h"
#endif
#define N2N_CAN_NAME_IFACE 1
#undef N2N_HAVE_DAEMON
#undef N2N_HAVE_SETUID
@ -47,6 +50,8 @@
#endif
#endif
#define PACKAGE_BUILDDATE (__DATE__ " " __TIME__)
#include <time.h>
@ -165,12 +170,13 @@ typedef struct ether_hdr ether_hdr_t;
#ifndef WIN32
typedef struct tuntap_dev {
int fd;
int if_idx;
uint8_t mac_addr[6];
uint32_t ip_addr, device_mask;
uint16_t mtu;
char dev_name[N2N_IFNAMSIZ];
int fd;
int if_idx;
n2n_mac_t mac_addr;
uint32_t ip_addr;
uint32_t device_mask;
uint16_t mtu;
char dev_name[N2N_IFNAMSIZ];
} tuntap_dev;
#define SOCKET int
@ -186,26 +192,31 @@ typedef char ipstr_t[32];
/** Common type used to hold stringified MAC addresses. */
#define N2N_MACSTR_SIZE 32
typedef char macstr_t[N2N_MACSTR_SIZE];
typedef char dec_ip_str_t[N2N_NETMASK_STR_SIZE];
typedef char dec_ip_bit_str_t[N2N_NETMASK_STR_SIZE + 4];
struct peer_info {
n2n_mac_t mac_addr;
n2n_sock_t sock;
int timeout;
time_t last_seen;
time_t last_p2p;
time_t last_sent_query;
uint64_t last_valid_time_stamp;
n2n_mac_t mac_addr;
n2n_ip_subnet_t dev_addr;
n2n_sock_t sock;
int timeout;
time_t last_seen;
time_t last_p2p;
time_t last_sent_query;
uint64_t last_valid_time_stamp;
UT_hash_handle hh; /* makes this structure hashable */
UT_hash_handle hh; /* makes this structure hashable */
};
typedef struct speck_context_t he_context_t;
typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];
typedef struct n2n_route {
in_addr_t net_addr;
int net_bitlen;
in_addr_t gateway;
in_addr_t net_addr;
uint8_t net_bitlen;
in_addr_t gateway;
} n2n_route_t;
typedef struct n2n_edge n2n_edge_t;
@ -247,8 +258,8 @@ typedef struct n2n_edge_callbacks {
typedef struct n2n_tuntap_priv_config {
char tuntap_dev_name[N2N_IFNAMSIZ];
char ip_mode[N2N_IF_MODE_SIZE];
char ip_addr[N2N_NETMASK_STR_SIZE];
char netmask[N2N_NETMASK_STR_SIZE];
dec_ip_str_t ip_addr;
dec_ip_str_t netmask;
char device_mac[N2N_MACNAMSIZ];
int mtu;
uint8_t got_s;
@ -261,30 +272,32 @@ typedef struct n2n_tuntap_priv_config {
/* *************************************************** */
typedef struct n2n_edge_conf {
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
n2n_route_t *routes; /**< Networks to route through n2n */
n2n_community_t community_name; /**< The community. 16 full octets. */
uint8_t header_encryption; /**< Header encryption indicator. */
he_context_t *header_encryption_ctx; /**< Header encryption cipher context. */
he_context_t *header_iv_ctx; /**< Header IV ecnryption cipher context, REMOVE as soon as seperte fileds for checksum and replay protection available */
n2n_transform_t transop_id; /**< The transop to use. */
uint16_t compression; /**< Compress outgoing data packets before encryption */
uint16_t num_routes; /**< Number of routes in routes */
uint8_t dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */
uint8_t allow_routing; /**< Accept packet no to interface address. */
uint8_t drop_multicast; /**< Multicast ethernet addresses. */
uint8_t disable_pmtu_discovery; /**< Disable the Path MTU discovery. */
uint8_t allow_p2p; /**< Allow P2P connection */
uint8_t sn_num; /**< Number of supernode addresses defined. */
uint8_t tos; /** TOS for sent packets */
char *encrypt_key;
int register_interval; /**< Interval for supernode registration, also used for UDP NAT hole punching. */
int register_ttl; /**< TTL for registration packet when UDP NAT hole punching through supernode. */
int local_port;
int mgmt_port;
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
n2n_route_t *routes; /**< Networks to route through n2n */
n2n_community_t community_name; /**< The community. 16 full octets. */
uint8_t header_encryption; /**< Header encryption indicator. */
he_context_t *header_encryption_ctx; /**< Header encryption cipher context. */
he_context_t *header_iv_ctx; /**< Header IV ecnryption cipher context, REMOVE as soon as seperte fileds for checksum and replay protection available */
n2n_transform_t transop_id; /**< The transop to use. */
uint16_t compression; /**< Compress outgoing data packets before encryption */
uint16_t num_routes; /**< Number of routes in routes */
uint8_t tuntap_ip_mode; /**< Interface IP address allocated mode, eg. DHCP. */
uint8_t allow_routing; /**< Accept packet no to interface address. */
uint8_t drop_multicast; /**< Multicast ethernet addresses. */
uint8_t disable_pmtu_discovery; /**< Disable the Path MTU discovery. */
uint8_t allow_p2p; /**< Allow P2P connection */
uint8_t sn_num; /**< Number of supernode addresses defined. */
uint8_t tos; /** TOS for sent packets */
char *encrypt_key;
int register_interval; /**< Interval for supernode registration, also used for UDP NAT hole punching. */
int register_ttl; /**< TTL for registration packet when UDP NAT hole punching through supernode. */
int local_port;
int mgmt_port;
} n2n_edge_conf_t;
struct n2n_edge_stats {
uint32_t tx_p2p;
uint32_t rx_p2p;
@ -298,44 +311,45 @@ struct n2n_edge {
n2n_edge_conf_t conf;
/* Status */
uint8_t sn_idx; /**< Currently active supernode. */
uint8_t sn_wait; /**< Whether we are waiting for a supernode response. */
size_t sup_attempts; /**< Number of remaining attempts to this supernode. */
tuntap_dev device; /**< All about the TUNTAP device */
n2n_trans_op_t transop; /**< The transop to use when encoding */
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
n2n_route_t *sn_route_to_clean; /**< Supernode route to clean */
n2n_edge_callbacks_t cb; /**< API callbacks */
void *user_data; /**< Can hold user data */
uint64_t sn_last_valid_time_stamp;/*< last valid time stamp from supernode */
uint8_t sn_idx; /**< Currently active supernode. */
uint8_t sn_wait; /**< Whether we are waiting for a supernode response. */
size_t sup_attempts; /**< Number of remaining attempts to this supernode. */
tuntap_dev device; /**< All about the TUNTAP device */
n2n_trans_op_t transop; /**< The transop to use when encoding */
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
n2n_route_t *sn_route_to_clean; /**< Supernode route to clean */
n2n_edge_callbacks_t cb; /**< API callbacks */
void *user_data; /**< Can hold user data */
uint64_t sn_last_valid_time_stamp;/**< last valid time stamp from supernode */
/* Sockets */
n2n_sock_t supernode;
int udp_sock;
int udp_mgmt_sock; /**< socket for status info. */
int udp_mgmt_sock; /**< socket for status info. */
#ifndef SKIP_MULTICAST_PEERS_DISCOVERY
n2n_sock_t multicast_peer; /**< Multicast peer group (for local edges) */
int udp_multicast_sock; /**< socket for local multicast registrations. */
int multicast_joined; /**< 1 if the group has been joined.*/
n2n_sock_t multicast_peer; /**< Multicast peer group (for local edges) */
int udp_multicast_sock; /**< socket for local multicast registrations. */
int multicast_joined; /**< 1 if the group has been joined.*/
#endif
/* Peers */
struct peer_info * known_peers; /**< Edges we are connected to. */
struct peer_info * pending_peers; /**< Edges we have tried to register with. */
struct peer_info * known_peers; /**< Edges we are connected to. */
struct peer_info * pending_peers; /**< Edges we have tried to register with. */
/* Timers */
time_t last_register_req; /**< Check if time to re-register with super*/
time_t last_p2p; /**< Last time p2p traffic was received. */
time_t last_sup; /**< Last time a packet arrived from supernode. */
time_t start_time; /**< For calculating uptime */
time_t last_register_req; /**< Check if time to re-register with super*/
time_t last_p2p; /**< Last time p2p traffic was received. */
time_t last_sup; /**< Last time a packet arrived from supernode. */
time_t start_time; /**< For calculating uptime */
/* Statistics */
struct n2n_edge_stats stats;
/* Tuntap config */
n2n_tuntap_priv_config_t tuntap_priv_conf;
struct n2n_edge_stats stats; /**< Statistics */
n2n_tuntap_priv_config_t tuntap_priv_conf; /**< Tuntap config */
};
typedef struct sn_stats
{
size_t errors; /* Number of errors encountered. */
@ -429,6 +443,8 @@ void tuntap_get_address(struct tuntap_dev *tuntap);
/* Utils */
char* intoa(uint32_t addr, char* buf, uint16_t buf_len);
uint32_t bitlen2mask(uint8_t bitlen);
uint8_t mask2bitlen(uint32_t mask);
char* macaddr_str(macstr_t buf, const n2n_mac_t mac);
int str2mac( uint8_t * outmac /* 6 bytes */, const char * s );
uint8_t is_multi_broadcast(const uint8_t * dest_mac);
@ -441,6 +457,7 @@ void print_edge_stats(const n2n_edge_t *eee);
/* Sockets */
char* sock_to_cstr( n2n_sock_str_t out,
const n2n_sock_t * sock );
char * ip_subnet_to_str(dec_ip_bit_str_t buf, const n2n_ip_subnet_t *ipaddr);
SOCKET open_socket(int local_port, int bind_any);
int sock_equal( const n2n_sock_t * a,
const n2n_sock_t * b );
@ -464,7 +481,9 @@ const n2n_edge_conf_t* edge_get_conf(const n2n_edge_t *eee);
void edge_term_conf(n2n_edge_conf_t *conf);
/* Public functions */
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv);
n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv);
void update_supernode_reg(n2n_edge_t * eee, time_t nowTime);
void readFromIPSocket(n2n_edge_t * eee, int in_sock);
void edge_term(n2n_edge_t *eee);
void edge_set_callbacks(n2n_edge_t *eee, const n2n_edge_callbacks_t *callbacks);
void edge_set_userdata(n2n_edge_t *eee, void *user_data);

View File

@ -101,6 +101,15 @@
#define N2N_SN_PKTBUF_SIZE 2048
/* The way TUNTAP allocated IP. */
#define TUNTAP_IP_MODE_SN_ASSIGN 0
#define TUNTAP_IP_MODE_STATIC 1
#define TUNTAP_IP_MODE_DHCP 2
/* Default network segment of the dhcp service provided by sn. */
#define N2N_SN_DHCP_NET_ADDR_DEFAULT "172.17.12.0"
#define N2N_SN_DHCP_NET_BIT_DEFAULT 24
/* ************************************** */
#define SUPERNODE_IP "127.0.0.1"

View File

@ -20,19 +20,10 @@
#define N2N_WIRE_H_
#include <stdlib.h>
#if defined(WIN32)
#include "win32/n2n_win32.h"
#if defined(__MINGW32__)
#ifndef _MSC_VER
/* Not included in Visual Studio 2008 */
#include <stdint.h>
#endif /* #ifdef __MINGW32__ */
#else /* #if defined(WIN32) */
#include <stdint.h>
#include <netinet/in.h>
#include <sys/socket.h> /* AF_INET and AF_INET6 */
#endif /* #if defined(WIN32) */
#endif
#define N2N_PKT_VERSION 2
#define N2N_DEFAULT_TTL 2 /* can be forwarded twice at most */
@ -51,6 +42,13 @@ typedef uint8_t n2n_cookie_t[N2N_COOKIE_SIZE];
typedef char n2n_sock_str_t[N2N_SOCKBUF_SIZE]; /* tracing string buffer */
#if defined(WIN32)
#include "win32/n2n_win32.h"
#else /* #if defined(WIN32) */
#include <netinet/in.h>
#include <sys/socket.h> /* AF_INET and AF_INET6 */
#endif /* #if defined(WIN32) */
typedef enum n2n_pc
{
n2n_ping=0, /* Not used */
@ -86,6 +84,12 @@ typedef enum n2n_pc
#define N2N_EINVAL -3
#define N2N_ENOSPACE -4
typedef struct n2n_ip_subnet {
uint32_t net_addr; /* Host order IP address. */
uint8_t net_bitlen; /* Subnet prefix. */
} n2n_ip_subnet_t;
typedef struct n2n_sock
{
uint8_t family; /* AF_INET or AF_INET6; or 0 if invalid */
@ -117,18 +121,18 @@ typedef struct n2n_common
typedef struct n2n_REGISTER
{
n2n_cookie_t cookie; /* Link REGISTER and REGISTER_ACK */
n2n_mac_t srcMac; /* MAC of registering party */
n2n_mac_t dstMac; /* MAC of target edge */
n2n_sock_t sock; /* REVISIT: unused? */
n2n_cookie_t cookie; /**< Link REGISTER and REGISTER_ACK */
n2n_mac_t srcMac; /**< MAC of registering party */
n2n_mac_t dstMac; /**< MAC of target edge */
n2n_sock_t sock; /**< REVISIT: unused? */
} n2n_REGISTER_t;
typedef struct n2n_REGISTER_ACK
{
n2n_cookie_t cookie; /* Return cookie from REGISTER */
n2n_mac_t srcMac; /* MAC of acknowledging party (supernode or edge) */
n2n_mac_t dstMac; /* Reflected MAC of registering edge from REGISTER */
n2n_sock_t sock; /* Supernode's view of edge socket (IP Addr, port) */
n2n_cookie_t cookie; /**< Return cookie from REGISTER */
n2n_mac_t srcMac; /**< MAC of acknowledging party (supernode or edge) */
n2n_mac_t dstMac; /**< Reflected MAC of registering edge from REGISTER */
n2n_sock_t sock; /**< Supernode's view of edge socket (IP Addr, port) */
} n2n_REGISTER_ACK_t;
typedef struct n2n_PACKET
@ -141,30 +145,30 @@ typedef struct n2n_PACKET
} n2n_PACKET_t;
/* Linked with n2n_register_super in n2n_pc_t. Only from edge to supernode. */
typedef struct n2n_REGISTER_SUPER
{
n2n_cookie_t cookie; /* Link REGISTER_SUPER and REGISTER_SUPER_ACK */
n2n_mac_t edgeMac; /* MAC to register with edge sending socket */
n2n_auth_t auth; /* Authentication scheme and tokens */
typedef struct n2n_REGISTER_SUPER {
n2n_cookie_t cookie; /**< Link REGISTER_SUPER and REGISTER_SUPER_ACK */
n2n_mac_t edgeMac; /**< MAC to register with edge sending socket */
n2n_ip_subnet_t dev_addr; /**< IP address of the tuntap adapter. */
n2n_auth_t auth; /**< Authentication scheme and tokens */
} n2n_REGISTER_SUPER_t;
/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */
typedef struct n2n_REGISTER_SUPER_ACK
{
n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */
n2n_mac_t edgeMac; /* MAC registered to edge sending socket */
uint16_t lifetime; /* How long the registration will live */
n2n_sock_t sock; /* Sending sockets associated with edgeMac */
/* The packet format provides additional supernode definitions here.
* uint8_t count, then for each count there is one
* n2n_sock_t.
*/
uint8_t num_sn; /* Number of supernodes that were send
/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */
typedef struct n2n_REGISTER_SUPER_ACK {
n2n_cookie_t cookie; /**< Return cookie from REGISTER_SUPER */
n2n_mac_t edgeMac; /**< MAC registered to edge sending socket */
n2n_ip_subnet_t dev_addr; /**< Assign an IP address to the tuntap adapter of edge. */
uint16_t lifetime; /**< How long the registration will live */
n2n_sock_t sock; /**< Sending sockets associated with edgeMac */
/** The packet format provides additional supernode definitions here.
* uint8_t count, then for each count there is one
* n2n_sock_t.
*/
uint8_t num_sn; /**< Number of supernodes that were send
* even if we cannot store them all. If
* non-zero then sn_bak is valid. */
n2n_sock_t sn_bak; /* Socket of the first backup supernode */
n2n_sock_t sn_bak; /**< Socket of the first backup supernode */
} n2n_REGISTER_SUPER_ACK_t;
@ -174,13 +178,14 @@ typedef struct n2n_REGISTER_SUPER_NAK
n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */
} n2n_REGISTER_SUPER_NAK_t;
typedef struct n2n_PEER_INFO
{
uint16_t aflags;
n2n_mac_t mac;
n2n_sock_t sock;
typedef struct n2n_PEER_INFO {
uint16_t aflags;
n2n_mac_t mac;
n2n_sock_t sock;
} n2n_PEER_INFO_t;
typedef struct n2n_QUERY_PEER
{
n2n_mac_t srcMac;

View File

@ -450,7 +450,7 @@ static int setOption(int optkey, char *optargument, n2n_tuntap_priv_config_t *ec
char cidr_net[64], gateway[64];
n2n_route_t route;
if(sscanf(optargument, "%63[^/]/%d:%63s", cidr_net, &route.net_bitlen, gateway) != 3) {
if(sscanf(optargument, "%63[^/]/%hhd:%63s", cidr_net, &route.net_bitlen, gateway) != 3) {
traceEvent(TRACE_WARNING, "Bad cidr/gateway format '%d'. See -h.", optargument);
break;
}
@ -818,7 +818,6 @@ int main(int argc, char* argv[]) {
#else
snprintf(ec.tuntap_dev_name, sizeof(ec.tuntap_dev_name), "edge0");
#endif
snprintf(ec.ip_mode, sizeof(ec.ip_mode), "static");
snprintf(ec.netmask, sizeof(ec.netmask), "255.255.255.0");
if((argc >= 2) && (argv[1][0] != '-')) {
@ -861,21 +860,6 @@ int main(int argc, char* argv[]) {
/* Random seed */
n2n_srand (n2n_seed());
if(0 == strcmp("dhcp", ec.ip_mode)) {
traceEvent(TRACE_NORMAL, "Dynamic IP address assignment enabled.");
conf.dyn_ip_mode = 1;
} else
traceEvent(TRACE_NORMAL, "ip_mode='%s'", ec.ip_mode);
if(!(
#ifdef __linux__
(ec.tuntap_dev_name[0] != 0) &&
#endif
(ec.ip_addr[0] != 0)
))
help();
#ifndef WIN32
/* If running suid root then we need to setuid before using the force. */
if(setuid(0) != 0)
@ -886,17 +870,51 @@ int main(int argc, char* argv[]) {
if(conf.encrypt_key && !strcmp((char*)conf.community_name, conf.encrypt_key))
traceEvent(TRACE_WARNING, "Community and encryption key must differ, otherwise security will be compromised");
if(tuntap_open(&tuntap, ec.tuntap_dev_name, ec.ip_mode, ec.ip_addr, ec.netmask, ec.device_mac, ec.mtu) < 0)
exit(1);
if((eee = edge_init(&tuntap, &conf, &rc)) == NULL) {
if((eee = edge_init(&conf, &rc)) == NULL) {
traceEvent(TRACE_ERROR, "Failed in edge_init");
exit(1);
}
memcpy(&(eee->tuntap_priv_conf), &ec, sizeof(ec));
if ((0 == strcmp("static", eee->tuntap_priv_conf.ip_mode)) ||
((eee->tuntap_priv_conf.ip_mode[0] == '\0') && (eee->tuntap_priv_conf.ip_addr[0] != '\0'))) {
traceEvent(TRACE_NORMAL, "Use manually set IP address.");
eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_STATIC;
} else if (0 == strcmp("dhcp", eee->tuntap_priv_conf.ip_mode)) {
traceEvent(TRACE_NORMAL, "Obtain IP from other edge DHCP services.");
eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_DHCP;
} else {
traceEvent(TRACE_NORMAL, "Automatically assign IP address by supernode.");
eee->conf.tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN;
do {
fd_set socket_mask;
struct timeval wait_time;
update_supernode_reg(eee, time(NULL));
FD_ZERO(&socket_mask);
FD_SET(eee->udp_sock, &socket_mask);
wait_time.tv_sec = SOCKET_TIMEOUT_INTERVAL_SECS;
wait_time.tv_usec = 0;
if (select(eee->udp_sock + 1, &socket_mask, NULL, NULL, &wait_time) > 0) {
if (FD_ISSET(eee->udp_sock, &socket_mask)) {
readFromIPSocket(eee, eee->udp_sock);
}
}
} while (eee->sn_wait);
eee->last_register_req = 0;
}
if (tuntap_open(&tuntap, eee->tuntap_priv_conf.tuntap_dev_name, eee->tuntap_priv_conf.ip_mode,
eee->tuntap_priv_conf.ip_addr, eee->tuntap_priv_conf.netmask,
eee->tuntap_priv_conf.device_mac, eee->tuntap_priv_conf.mtu) < 0) exit(1);
traceEvent(TRACE_NORMAL, "Local tuntap IP: %s, Mask: %s",
eee->tuntap_priv_conf.ip_addr, eee->tuntap_priv_conf.netmask);
memcpy(&eee->device, &tuntap, sizeof(tuntap));
// hexdump((unsigned char*)&tuntap,sizeof(tuntap_dev));
#ifndef WIN32
if(ec.daemon) {
if(eee->tuntap_priv_conf.daemon) {
setUseSyslog(1); /* traceEvent output now goes to syslog. */
daemonize();
}
@ -919,13 +937,13 @@ int main(int argc, char* argv[]) {
#endif
#endif /* HAVE_LIBCAP */
if((ec.userid != 0) || (ec.groupid != 0)) {
if((eee->tuntap_priv_conf.userid != 0) || (eee->tuntap_priv_conf.groupid != 0)) {
traceEvent(TRACE_NORMAL, "Dropping privileges to uid=%d, gid=%d",
(signed int)ec.userid, (signed int)ec.groupid);
(signed int)eee->tuntap_priv_conf.userid, (signed int)eee->tuntap_priv_conf.groupid);
/* Finished with the need for root privileges. Drop to unprivileged user. */
if((setgid(ec.groupid) != 0)
|| (setuid(ec.userid) != 0)) {
if((setgid(eee->tuntap_priv_conf.groupid) != 0)
|| (setuid(eee->tuntap_priv_conf.userid) != 0)) {
traceEvent(TRACE_ERROR, "Unable to drop privileges [%u/%s]", errno, strerror(errno));
exit(1);
}
@ -961,10 +979,8 @@ int main(int argc, char* argv[]) {
/* Cleanup */
edge_term(eee);
edge_term_conf(&conf);
tuntap_close(&tuntap);
if(conf.encrypt_key) free(conf.encrypt_key);
edge_term_conf(&eee->conf);
tuntap_close(&eee->device);
return(rc);
}

View File

@ -167,7 +167,7 @@ static int is_ip6_discovery(const void * buf, size_t bufsize) {
*
* This also initialises the NULL transform operation opstruct.
*/
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv) {
n2n_edge_t* edge_init(const n2n_edge_conf_t *conf, int *rv) {
n2n_transform_t transop_id = conf->transop_id;
n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t));
int rc = -1, i;
@ -187,7 +187,6 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
#endif
memcpy(&eee->conf, conf, sizeof(*conf));
memcpy(&eee->device, dev, sizeof(*dev));
eee->start_time = time(NULL);
eee->known_peers = NULL;
@ -207,11 +206,11 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
// zstd does not require initialization. if it were required, this would be a good place
#endif
for(i=0; i<conf->sn_num; ++i)
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (conf->sn_ip_array[i]));
for(i=0; i<eee->conf.sn_num; ++i)
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (eee->conf.sn_ip_array[i]));
/* Set the active supernode */
supernode2addr(&(eee->supernode), conf->sn_ip_array[eee->sn_idx]);
supernode2addr(&(eee->supernode), eee->conf.sn_ip_array[eee->sn_idx]);
/* Set active transop */
switch(transop_id) {
@ -243,18 +242,18 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
/* Set the key schedule (context) for header encryption if enabled */
if(conf->header_encryption == HEADER_ENCRYPTION_ENABLED) {
traceEvent(TRACE_NORMAL, "Header encryption is enabled.");
packet_header_setup_key ((char *)(conf->community_name), &(eee->conf.header_encryption_ctx),&(eee->conf.header_iv_ctx));
packet_header_setup_key ((char *)(eee->conf.community_name), &(eee->conf.header_encryption_ctx),&(eee->conf.header_iv_ctx));
}
if(eee->transop.no_encryption)
traceEvent(TRACE_WARNING, "Encryption is disabled in edge");
if(edge_init_sockets(eee, conf->local_port, conf->mgmt_port, conf->tos) < 0) {
if(edge_init_sockets(eee, eee->conf.local_port, eee->conf.mgmt_port, eee->conf.tos) < 0) {
traceEvent(TRACE_ERROR, "socket setup failed");
goto edge_init_error;
}
if(edge_init_routes(eee, conf->routes, conf->num_routes) < 0) {
if(edge_init_routes(eee, eee->conf.routes, eee->conf.num_routes) < 0) {
traceEvent(TRACE_ERROR, "routes setup failed");
goto edge_init_error;
}
@ -389,7 +388,7 @@ static const int definitely_from_supernode = 1;
* and verify it (and also update, if applicable).
*/
static int find_peer_time_stamp_and_verify (n2n_edge_t * eee,
int from_supernode, n2n_mac_t mac,
int from_supernode, const n2n_mac_t mac,
uint64_t stamp) {
uint64_t * previous_stamp = NULL;
@ -628,8 +627,8 @@ int is_empty_ip_address(const n2n_sock_t * sock) {
/* ************************************** */
static n2n_mac_t broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0};
static const n2n_mac_t broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
static const n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0};
/** Check if a known peer socket has changed and possibly register again.
*/
@ -736,41 +735,44 @@ static void check_join_multicast_group(n2n_edge_t *eee) {
/** Send a REGISTER_SUPER packet to the current supernode. */
static void send_register_super(n2n_edge_t *eee, const n2n_sock_t *supernode, int sn_idx) {
uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0};
size_t idx;
/* ssize_t sent; */
n2n_common_t cmn;
n2n_REGISTER_SUPER_t reg;
n2n_sock_str_t sockbuf;
uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0};
size_t idx;
/* ssize_t sent; */
n2n_common_t cmn;
n2n_REGISTER_SUPER_t reg;
n2n_sock_str_t sockbuf;
memset(&cmn, 0, sizeof(cmn));
memset(&reg, 0, sizeof(reg));
cmn.ttl=N2N_DEFAULT_TTL;
cmn.pc = n2n_register_super;
cmn.flags = 0;
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
memset(&cmn, 0, sizeof(cmn));
memset(&reg, 0, sizeof(reg));
for (idx = 0; (sn_idx==0) && (idx < N2N_COOKIE_SIZE); ++idx)
eee->last_cookie[idx] = n2n_rand() % 0xff;
cmn.ttl = N2N_DEFAULT_TTL;
cmn.pc = n2n_register_super;
cmn.flags = 0;
memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
memcpy(reg.cookie, eee->last_cookie, N2N_COOKIE_SIZE);
reg.auth.scheme=0; /* No auth yet */
for (idx = 0; (sn_idx==0) && (idx < N2N_COOKIE_SIZE); ++idx)
eee->last_cookie[idx] = n2n_rand() % 0xff;
idx=0;
encode_mac(reg.edgeMac, &idx, eee->device.mac_addr);
memcpy(reg.cookie, eee->last_cookie, N2N_COOKIE_SIZE);
reg.dev_addr.net_addr = ntohl(eee->device.ip_addr);
reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask));
reg.auth.scheme = 0; /* No auth yet */
idx=0;
encode_REGISTER_SUPER(pktbuf, &idx, &cmn, &reg);
idx = 0;
encode_mac(reg.edgeMac, &idx, eee->device.mac_addr);
traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s",
sock_to_cstr(sockbuf, supernode));
idx = 0;
encode_REGISTER_SUPER(pktbuf, &idx, &cmn, &reg);
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx,
eee->conf.header_iv_ctx,
time_stamp (), pearson_hash_16 (pktbuf, idx));
traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s",
sock_to_cstr(sockbuf, supernode));
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, supernode);
if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
packet_header_encrypt(pktbuf, idx, eee->conf.header_encryption_ctx,
eee->conf.header_iv_ctx,
time_stamp(), pearson_hash_16(pktbuf, idx));
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, supernode);
}
/* ************************************** */
@ -904,7 +906,7 @@ static void send_register_ack(n2n_edge_t * eee,
*
* This is frequently called by the main loop.
*/
static void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
u_int sn_idx;
if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->conf.register_interval/10)))) {
@ -1449,7 +1451,7 @@ void edge_send_packet2net(n2n_edge_t * eee,
pkt.compression = N2N_COMPRESSION_ID_NONE;
if(eee->conf.compression) {
uint8_t * compression_buffer;
uint8_t * compression_buffer = NULL;
int32_t compression_len;
switch (eee->conf.compression) {
@ -1588,7 +1590,7 @@ void edge_read_from_tap(n2n_edge_t * eee) {
/* ************************************** */
/** Read a datagram from the main UDP socket to the internet. */
static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
n2n_common_t cmn; /* common fields in the packet header */
n2n_sock_str_t sockbuf1;
@ -1750,14 +1752,14 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
* to double check this.
*/
traceEvent(TRACE_DEBUG, "Got P2P register");
traceEvent(TRACE_NORMAL, "[P2P] Rx REGISTER from %s", sock_to_cstr(sockbuf1, &sender));
traceEvent(TRACE_INFO, "[P2P] Rx REGISTER from %s", sock_to_cstr(sockbuf1, &sender));
find_and_remove_peer(&eee->pending_peers, reg.srcMac);
/* NOTE: only ACK to peers */
send_register_ack(eee, orig_sender, &reg);
}
else {
traceEvent(TRACE_NORMAL, "[PsP] Rx REGISTER src=%s dst=%s from sn=%s (edge:%s)",
traceEvent(TRACE_INFO, "[PsP] Rx REGISTER src=%s dst=%s from sn=%s (edge:%s)",
macaddr_str(mac_buf1, reg.srcMac), macaddr_str(mac_buf2, reg.dstMac),
sock_to_cstr(sockbuf1, &sender), sock_to_cstr(sockbuf2, orig_sender));
}
@ -1793,7 +1795,13 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
}
case MSG_TYPE_REGISTER_SUPER_ACK:
{
// Indicates successful connection between the edge and SN nodes
in_addr_t net;
char * ip_str = NULL;
n2n_REGISTER_SUPER_ACK_t ra;
memset(&ra, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
// Indicates successful connection between the edge and SN nodes
static int bTrace = 1;
if (bTrace)
{
@ -1801,7 +1809,6 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
bTrace = 0;
}
n2n_REGISTER_SUPER_ACK_t ra;
if(eee->sn_wait)
{
@ -1839,6 +1846,20 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
eee->last_sup = now;
eee->sn_wait=0;
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */
if (eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_SN_ASSIGN) {
if ((ra.dev_addr.net_addr != 0) && (ra.dev_addr.net_bitlen != 0)) {
net = htonl(ra.dev_addr.net_addr);
if ((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) {
strncpy(eee->tuntap_priv_conf.ip_addr, ip_str,
N2N_NETMASK_STR_SIZE);
}
net = htonl(bitlen2mask(ra.dev_addr.net_bitlen));
if ((ip_str = inet_ntoa(*(struct in_addr *) &net)) != NULL) {
strncpy(eee->tuntap_priv_conf.netmask, ip_str,
N2N_NETMASK_STR_SIZE);
}
}
}
if(eee->cb.sn_registration_updated)
eee->cb.sn_registration_updated(eee, now, &sender);
@ -1857,7 +1878,8 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with no outstanding REGISTER_SUPER.");
}
break;
} case MSG_TYPE_PEER_INFO: {
}
case MSG_TYPE_PEER_INFO: {
n2n_PEER_INFO_t pi;
struct peer_info * scan;
decode_PEER_INFO( &pi, &cmn, udp_buf, &rem, &idx );
@ -2024,7 +2046,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
HASH_COUNT(eee->known_peers));
}
if(eee->conf.dyn_ip_mode &&
if((eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_DHCP) &&
((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) {
uint32_t old_ip = eee->device.ip_addr;
@ -2535,28 +2557,30 @@ static void edge_cleanup_routes(n2n_edge_t *eee) {
/* ************************************** */
void edge_init_conf_defaults(n2n_edge_conf_t *conf) {
memset(conf, 0, sizeof(*conf));
memset(conf, 0, sizeof(*conf));
conf->local_port = 0 /* any port */;
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
conf->transop_id = N2N_TRANSFORM_ID_NULL;
conf->header_encryption = HEADER_ENCRYPTION_NONE;
conf->compression = N2N_COMPRESSION_ID_NONE;
conf->drop_multicast = 1;
conf->allow_p2p = 1;
conf->disable_pmtu_discovery = 1;
conf->register_interval = REGISTER_SUPER_INTERVAL_DFL;
conf->local_port = 0 /* any port */;
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
conf->transop_id = N2N_TRANSFORM_ID_NULL;
conf->header_encryption = HEADER_ENCRYPTION_NONE;
conf->compression = N2N_COMPRESSION_ID_NONE;
conf->drop_multicast = 1;
conf->allow_p2p = 1;
conf->disable_pmtu_discovery = 1;
conf->register_interval = REGISTER_SUPER_INTERVAL_DFL;
conf->tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN;
if(getenv("N2N_KEY")) {
conf->encrypt_key = strdup(getenv("N2N_KEY"));
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH;
}
if (getenv("N2N_KEY")) {
conf->encrypt_key = strdup(getenv("N2N_KEY"));
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH;
}
}
/* ************************************** */
void edge_term_conf(n2n_edge_conf_t *conf) {
if(conf->routes) free(conf->routes);
if (conf->routes) free(conf->routes);
if (conf->encrypt_key) free(conf->encrypt_key);
}
/* ************************************** */
@ -2608,7 +2632,7 @@ int quick_edge_init(char *device_name, char *community_name,
return(-2);
/* Init edge */
if((eee = edge_init(&tuntap, &conf, &rv)) == NULL)
if((eee = edge_init(&conf, &rv)) == NULL)
goto quick_edge_init_end;
rv = run_edge_loop(eee, keep_on_running);

View File

@ -33,7 +33,7 @@ int main()
snprintf((char *)conf.community_name, sizeof(conf.community_name), "%s", "mycommunity"); // Community to connect to
conf.disable_pmtu_discovery = 1; // Whether to disable the path MTU discovery
conf.drop_multicast = 0; // Whether to disable multicast
conf.dyn_ip_mode = 0; // Whether the IP address is set dynamically (see IP mode; 0 if static, 1 if dynamic)
conf.tuntap_ip_mode = TUNTAP_IP_MODE_SN_ASSIGN; // How to set the IP address
conf.encrypt_key = "mysecret"; // Secret to decrypt & encrypt with
conf.local_port = 0; // What port to use (0 = any port)
conf.mgmt_port = N2N_EDGE_MGMT_PORT; // Edge management port (5644 by default)
@ -59,7 +59,7 @@ int main()
return -1;
}
eee = edge_init(&tuntap, &conf, &rc);
eee = edge_init(&conf, &rc);
if (eee == NULL)
{
exit(1);

View File

@ -185,6 +185,29 @@ char* intoa(uint32_t /* host order */ addr, char* buf, uint16_t buf_len) {
return(retStr);
}
/** Convert subnet prefix bit length to host order subnet mask. */
uint32_t bitlen2mask(uint8_t bitlen) {
uint8_t i;
uint32_t mask = 0;
for (i = 1; i <= bitlen; ++i) {
mask |= 1 << (32 - i);
}
return mask;
}
/** Convert host order subnet mask to subnet prefix bit length. */
uint8_t mask2bitlen(uint32_t mask) {
uint8_t i, bitlen = 0;
for (i = 0; i < 32; ++i) {
if ((mask << i) & 0x80000000) ++bitlen;
else break;
}
return bitlen;
}
/* *********************************************** */
char * macaddr_str(macstr_t buf,
@ -231,21 +254,21 @@ char* msg_type2str(uint16_t msg_type) {
/* *********************************************** */
void hexdump(const uint8_t * buf, size_t len)
{
size_t i;
void hexdump(const uint8_t *buf, size_t len) {
size_t i;
if(0 == len) { return; }
if (0 == len) { return; }
for(i=0; i<len; i++)
{
if((i > 0) &&((i % 16) == 0)) { printf("\n"); }
printf("%02X ", buf[i] & 0xFF);
}
printf("\n");
printf("-----------------------------------------------\n");
for (i = 0; i < len; i++) {
if ((i > 0) && ((i % 16) == 0)) { printf("\n"); }
printf("%02X ", buf[i] & 0xFF);
}
printf("\n");
printf("-----------------------------------------------\n");
}
/* *********************************************** */
void print_n2n_version() {
@ -360,6 +383,17 @@ extern char * sock_to_cstr(n2n_sock_str_t out,
}
}
char *ip_subnet_to_str(dec_ip_bit_str_t buf, const n2n_ip_subnet_t *ipaddr) {
snprintf(buf, sizeof(dec_ip_bit_str_t), "%hhu.%hhu.%hhu.%hhu/%hhu",
(uint8_t) ((ipaddr->net_addr >> 24) & 0xFF),
(uint8_t) ((ipaddr->net_addr >> 16) & 0xFF),
(uint8_t) ((ipaddr->net_addr >> 8) & 0xFF),
(uint8_t) (ipaddr->net_addr & 0xFF),
ipaddr->net_bitlen);
return buf;
}
/* @return 1 if the two sockets are equivalent. */
int sock_equal(const n2n_sock_t * a,
const n2n_sock_t * b) {
@ -383,7 +417,7 @@ int sock_equal(const n2n_sock_t * a,
/* *********************************************** */
#if defined(WIN32) && !defined(__GNUC__)
#if defined(WIN32)
int gettimeofday(struct timeval *tp, void *tzp) {
time_t clock;
struct tm tm;

View File

@ -98,8 +98,8 @@ uint64_t n2n_rand () {
state yet, a call to n2n_srand ( n2n_seed() ) would do. */
uint64_t n2n_seed (void) {
uint64_t seed;
uint64_t ret;
uint64_t seed = 0;
uint64_t ret = 0;
size_t i;
#ifdef SYS_getrandom

159
src/sn.c
View File

@ -123,100 +123,137 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
/** Help message to print if the command line arguments are not valid. */
static void help() {
print_n2n_version();
print_n2n_version();
printf("supernode <config file> (see supernode.conf)\n"
"or\n"
);
printf("supernode ");
printf("-l <local port> ");
printf("-c <path> ");
printf("supernode <config file> (see supernode.conf)\n"
"or\n"
);
printf("supernode ");
printf("-l <local port> ");
printf("-c <path> ");
#if defined(N2N_HAVE_DAEMON)
printf("[-f] ");
printf("[-f] ");
#endif
#ifndef WIN32
printf("[-u <uid> -g <gid>] ");
printf("[-u <uid> -g <gid>] ");
#endif /* ifndef WIN32 */
printf("[-t <mgmt port>] ");
printf("[-v] ");
printf("\n\n");
printf("[-t <mgmt port>] ");
printf("[-d <net/bit>] ");
printf("[-v] ");
printf("\n\n");
printf("-l <port>\tSet UDP main listen port to <port>\n");
printf("-c <path>\tFile containing the allowed communities.\n");
printf("-l <port> | Set UDP main listen port to <port>\n");
printf("-c <path> | File containing the allowed communities.\n");
#if defined(N2N_HAVE_DAEMON)
printf("-f \tRun in foreground.\n");
printf("-f | Run in foreground.\n");
#endif /* #if defined(N2N_HAVE_DAEMON) */
#ifndef WIN32
printf("-u <UID>\tUser ID (numeric) to use when privileges are dropped.\n");
printf("-g <GID>\tGroup ID (numeric) to use when privileges are dropped.\n");
printf("-u <UID> | User ID (numeric) to use when privileges are dropped.\n");
printf("-g <GID> | Group ID (numeric) to use when privileges are dropped.\n");
#endif /* ifndef WIN32 */
printf("-t <port>\tManagement UDP Port (for multiple supernodes on a machine).\n");
printf("-v \tIncrease verbosity. Can be used multiple times.\n");
printf("-h \tThis help message.\n");
printf("\n");
printf("-t <port> | Management UDP Port (for multiple supernodes on a machine).\n");
printf("-d <net/bit> | Subnet that provides dhcp service for edge. eg. -d 172.17.12.0/24\n");
printf("-v | Increase verbosity. Can be used multiple times.\n");
printf("-h | This help message.\n");
printf("\n");
exit(1);
exit(1);
}
/* *************************************************** */
static int setOption(int optkey, char *_optarg, n2n_sn_t *sss) {
//traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, _optarg ? _optarg : "");
//traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, _optarg ? _optarg : "");
switch(optkey) {
case 'l': /* local-port */
sss->lport = atoi(_optarg);
break;
switch (optkey) {
case 'l': /* local-port */
sss->lport = atoi(_optarg);
break;
case 't': /* mgmt-port */
sss->mport = atoi(_optarg);
break;
case 't': /* mgmt-port */
sss->mport = atoi(_optarg);
break;
case 'd': {
dec_ip_str_t ip_str = {'\0'};
in_addr_t net;
uint8_t bitlen;
if (sscanf(_optarg, "%15[^/]/%hhu", ip_str, &bitlen) != 2) {
traceEvent(TRACE_WARNING, "Bad net/bit format '%s'. See -h.", _optarg);
break;
}
net = inet_addr(ip_str);
if ((net < 0) || (net == INADDR_NONE) || (net == INADDR_ANY)) {
traceEvent(TRACE_WARNING, "Bad network '%s' in '%s', Use default: '%s/%d'",
ip_str, _optarg,
N2N_SN_DHCP_NET_ADDR_DEFAULT, N2N_SN_DHCP_NET_BIT_DEFAULT);
break;
}
if (bitlen > 32) {
traceEvent(TRACE_WARNING, "Bad prefix '%hhu' in '%s', Use default: '%s/%d'",
bitlen, _optarg,
N2N_SN_DHCP_NET_ADDR_DEFAULT, N2N_SN_DHCP_NET_BIT_DEFAULT);
break;
}
traceEvent(TRACE_NORMAL, "The subnet of DHCP service is: '%s/%hhu'.", ip_str, bitlen);
sss->dhcp_addr.net_addr = ntohl(net);
sss->dhcp_addr.net_bitlen = bitlen;
break;
}
#ifndef WIN32
case 'u': /* unprivileged uid */
sss->userid = atoi(_optarg);
break;
case 'u': /* unprivileged uid */
sss->userid = atoi(_optarg);
break;
case 'g': /* unprivileged uid */
sss->groupid = atoi(_optarg);
break;
case 'g': /* unprivileged uid */
sss->groupid = atoi(_optarg);
break;
#endif
case 'c': /* community file */
load_allowed_sn_community(sss, _optarg);
break;
case 'c': /* community file */
load_allowed_sn_community(sss, _optarg);
break;
case 'f': /* foreground */
sss->daemon = 0;
break;
case 'f': /* foreground */
sss->daemon = 0;
break;
case 'h': /* help */
help();
break;
case 'h': /* help */
help();
break;
case 'v': /* verbose */
setTraceLevel(getTraceLevel() + 1);
break;
case 'v': /* verbose */
setTraceLevel(getTraceLevel() + 1);
break;
default:
traceEvent(TRACE_WARNING, "Unknown option -%c: Ignored.", (char)optkey);
return(-1);
}
default:
traceEvent(TRACE_WARNING, "Unknown option -%c: Ignored.", (char) optkey);
return (-1);
}
return(0);
return (0);
}
/* *********************************************** */
static const struct option long_options[] = {
{ "communities", required_argument, NULL, 'c' },
{ "foreground", no_argument, NULL, 'f' },
{ "local-port", required_argument, NULL, 'l' },
{ "mgmt-port", required_argument, NULL, 't' },
{ "help" , no_argument, NULL, 'h' },
{ "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
{"communities", required_argument, NULL, 'c'},
{"foreground", no_argument, NULL, 'f'},
{"local-port", required_argument, NULL, 'l'},
{"mgmt-port", required_argument, NULL, 't'},
{"dhcp", required_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
{"verbose", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0}
};
/* *************************************************** */
@ -225,7 +262,7 @@ static const struct option long_options[] = {
static int loadFromCLI(int argc, char * const argv[], n2n_sn_t *sss) {
u_char c;
while((c = getopt_long(argc, argv, "fl:u:g:t:c:vh",
while((c = getopt_long(argc, argv, "fl:u:g:t:d:c:vh",
long_options, NULL)) != '?') {
if(c == 255) break;
setOption(c, optarg, sss);

View File

@ -47,7 +47,7 @@ static int try_broadcast(n2n_sn_t * sss,
static uint16_t reg_lifetime(n2n_sn_t *sss);
static int update_edge(n2n_sn_t *sss,
const n2n_mac_t edgeMac,
const n2n_REGISTER_SUPER_t* reg,
struct sn_community *comm,
const n2n_sock_t *sender_sock,
time_t now);
@ -204,23 +204,25 @@ static int try_broadcast(n2n_sn_t * sss,
/** Initialise the supernode structure */
int sn_init(n2n_sn_t *sss)
{
int sn_init(n2n_sn_t *sss) {
#ifdef WIN32
initWin32();
initWin32();
#endif
pearson_hash_init();
pearson_hash_init();
memset(sss, 0, sizeof(n2n_sn_t));
memset(sss, 0, sizeof(n2n_sn_t));
sss->daemon = 1; /* By defult run as a daemon. */
sss->lport = N2N_SN_LPORT_DEFAULT;
sss->mport = N2N_SN_MGMT_PORT;
sss->sock = -1;
sss->mgmt_sock = -1;
sss->daemon = 1; /* By defult run as a daemon. */
sss->lport = N2N_SN_LPORT_DEFAULT;
sss->mport = N2N_SN_MGMT_PORT;
sss->sock = -1;
sss->mgmt_sock = -1;
sss->dhcp_addr.net_addr = inet_addr(N2N_SN_DHCP_NET_ADDR_DEFAULT);
sss->dhcp_addr.net_addr = ntohl(sss->dhcp_addr.net_addr);
sss->dhcp_addr.net_bitlen = N2N_SN_DHCP_NET_BIT_DEFAULT;
return 0; /* OK */
return 0; /* OK */
}
/** Deinitialise the supernode structure and deallocate any memory owned by
@ -274,61 +276,101 @@ static uint16_t reg_lifetime(n2n_sn_t *sss)
/** Update the edge table with the details of the edge which contacted the
* supernode. */
static int update_edge(n2n_sn_t *sss,
const n2n_mac_t edgeMac,
const n2n_REGISTER_SUPER_t* reg,
struct sn_community *comm,
const n2n_sock_t *sender_sock,
time_t now)
{
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
struct peer_info *scan;
time_t now) {
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
struct peer_info *scan;
traceEvent(TRACE_DEBUG, "update_edge for %s [%s]",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
traceEvent(TRACE_DEBUG, "update_edge for %s [%s]",
macaddr_str(mac_buf, reg->edgeMac),
sock_to_cstr(sockbuf, sender_sock));
HASH_FIND_PEER(comm->edges, edgeMac, scan);
HASH_FIND_PEER(comm->edges, reg->edgeMac, scan);
if (NULL == scan)
{
/* Not known */
if (NULL == scan) {
/* Not known */
scan = (struct peer_info *)calloc(1,
sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */
scan = (struct peer_info *) calloc(1,
sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */
memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t));
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
scan->last_valid_time_stamp = initial_time_stamp ();
memcpy(&(scan->mac_addr), reg->edgeMac, sizeof(n2n_mac_t));
scan->dev_addr.net_addr = reg->dev_addr.net_addr;
scan->dev_addr.net_bitlen = reg->dev_addr.net_bitlen;
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
scan->last_valid_time_stamp = initial_time_stamp();
HASH_ADD_PEER(comm->edges, scan);
HASH_ADD_PEER(comm->edges, scan);
traceEvent(TRACE_INFO, "update_edge created %s ==> %s",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
else
{
/* Known */
if (!sock_equal(sender_sock, &(scan->sock)))
{
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
traceEvent(TRACE_INFO, "update_edge created %s ==> %s",
macaddr_str(mac_buf, reg->edgeMac),
sock_to_cstr(sockbuf, sender_sock));
} else {
/* Known */
if (!sock_equal(sender_sock, &(scan->sock))) {
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
traceEvent(TRACE_INFO, "update_edge updated %s ==> %s",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
else
{
traceEvent(TRACE_DEBUG, "update_edge unchanged %s ==> %s",
macaddr_str(mac_buf, edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
}
traceEvent(TRACE_INFO, "update_edge updated %s ==> %s",
macaddr_str(mac_buf, reg->edgeMac),
sock_to_cstr(sockbuf, sender_sock));
} else {
traceEvent(TRACE_DEBUG, "update_edge unchanged %s ==> %s",
macaddr_str(mac_buf, reg->edgeMac),
sock_to_cstr(sockbuf, sender_sock));
}
}
scan->last_seen = now;
return 0;
scan->last_seen = now;
return 0;
}
static signed int peer_tap_ip_sort(struct peer_info *a, struct peer_info *b) {
uint32_t a_host_id = a->dev_addr.net_addr & (~bitlen2mask(a->dev_addr.net_bitlen));
uint32_t b_host_id = b->dev_addr.net_addr & (~bitlen2mask(b->dev_addr.net_bitlen));
return ((signed int)a_host_id - (signed int)b_host_id);
}
/** The IP address assigned to the edge by the DHCP function of sn. */
static int assign_one_ip_addr(n2n_sn_t *sss,
struct sn_community *comm,
n2n_ip_subnet_t *ipaddr) {
struct peer_info *peer, *tmpPeer;
uint32_t net_id, mask, max_host, host_id = 1;
dec_ip_bit_str_t ip_bit_str = {'\0'};
mask = bitlen2mask(sss->dhcp_addr.net_bitlen);
net_id = sss->dhcp_addr.net_addr & mask;
max_host = ~mask;
HASH_SORT(comm->edges, peer_tap_ip_sort);
HASH_ITER(hh, comm->edges, peer, tmpPeer) {
if ((peer->dev_addr.net_addr & bitlen2mask(peer->dev_addr.net_bitlen)) == net_id) {
if (host_id >= max_host) {
traceEvent(TRACE_WARNING, "No assignable IP to edge tap adapter.");
return -1;
}
if (peer->dev_addr.net_addr == 0) {
continue;
}
if ((peer->dev_addr.net_addr & max_host) == host_id) {
++host_id;
} else {
break;
}
}
}
ipaddr->net_addr = net_id | host_id;
ipaddr->net_bitlen = sss->dhcp_addr.net_bitlen;
traceEvent(TRACE_INFO, "Assign IP %s to tap adapter of edge.", ip_subnet_to_str(ip_bit_str, ipaddr));
return 0;
}
/***
*
* For a given packet, find the apporopriate internal last valid time stamp for lookup
@ -418,89 +460,89 @@ static int process_mgmt(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *mgmt_buf,
size_t mgmt_size,
time_t now)
{
char resbuf[N2N_SN_PKTBUF_SIZE];
size_t ressize = 0;
uint32_t num_edges = 0;
uint32_t num = 0;
struct sn_community *community, *tmp;
struct peer_info * peer, *tmpPeer;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
time_t now) {
char resbuf[N2N_SN_PKTBUF_SIZE];
size_t ressize = 0;
uint32_t num_edges = 0;
uint32_t num = 0;
struct sn_community *community, *tmp;
struct peer_info *peer, *tmpPeer;
macstr_t mac_buf;
n2n_sock_str_t sockbuf;
dec_ip_bit_str_t ip_bit_str = {'\0'};
traceEvent(TRACE_DEBUG, "process_mgmt");
traceEvent(TRACE_DEBUG, "process_mgmt");
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"----------------\n");
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"\tid tun_tap MAC edge last_seen\n");
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"-------------------------------------------------------------------------------------\n");
HASH_ITER(hh, sss->communities, community, tmp) {
num_edges += HASH_COUNT(community->edges);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"community: %s\n", community->community);
sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize);
ressize = 0;
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"uptime %lu\n", (now - sss->start_time));
num = 0;
HASH_ITER(hh, community->edges, peer, tmpPeer) {
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"\t%-4u %-18s %-17s %-21s %lu\n",
++num, ip_subnet_to_str(ip_bit_str, &peer->dev_addr),
macaddr_str(mac_buf, peer->mac_addr),
sock_to_cstr(sockbuf, &(peer->sock)), now - peer->last_seen);
HASH_ITER(hh, sss->communities, community, tmp)
{
num_edges += HASH_COUNT(community->edges);
}
sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize);
ressize = 0;
}
}
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"-------------------------------------------------------------------------------------\n");
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"edges %u\n",
num_edges);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"uptime %lu | ", (now - sss->start_time));
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"errors %u\n",
(unsigned int)sss->stats.errors);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"edges %u | ",
num_edges);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"reg_sup %u\n",
(unsigned int)sss->stats.reg_super);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"reg_sup %u | ",
(unsigned int) sss->stats.reg_super);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"reg_nak %u\n",
(unsigned int)sss->stats.reg_super_nak);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"reg_nak %u | ",
(unsigned int) sss->stats.reg_super_nak);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"fwd %u\n",
(unsigned int)sss->stats.fwd);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"errors %u \n",
(unsigned int) sss->stats.errors);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"broadcast %u\n",
(unsigned int)sss->stats.broadcast);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"fwd %u | ",
(unsigned int) sss->stats.fwd);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"last fwd %lu sec ago\n",
(long unsigned int)(now - sss->stats.last_fwd));
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"broadcast %u | ",
(unsigned int) sss->stats.broadcast);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"last reg %lu sec ago\n",
(long unsigned int)(now - sss->stats.last_reg_super));
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"cur_cmnts %u\n", HASH_COUNT(sss->communities));
ressize += snprintf(resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"cur_cmnts %u\n", HASH_COUNT(sss->communities));
HASH_ITER(hh, sss->communities, community, tmp) {
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"community: %s\n", community->community);
sendto_mgmt(sss, sender_sock, (const uint8_t *)resbuf, ressize);
ressize = 0;
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"last fwd %lu sec ago\n",
(long unsigned int) (now - sss->stats.last_fwd));
num = 0;
HASH_ITER(hh, community->edges, peer, tmpPeer) {
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"\t[id: %u][MAC: %s][edge: %s][last seen: %lu sec ago]\n",
++num, macaddr_str(mac_buf, peer->mac_addr),
sock_to_cstr(sockbuf, &(peer->sock)), now-peer->last_seen);
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
"last reg %lu sec ago\n\n",
(long unsigned int) (now - sss->stats.last_reg_super));
sendto_mgmt(sss, sender_sock, (const uint8_t *)resbuf, ressize);
ressize = 0;
}
}
sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize);
ressize += snprintf(resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
"\n");
sendto_mgmt(sss, sender_sock, (const uint8_t *)resbuf, ressize);
return 0;
return 0;
}
static int sendto_mgmt(n2n_sn_t *sss,
const struct sockaddr_in *sender_sock,
const uint8_t *mgmt_buf,
@ -537,6 +579,7 @@ static int process_udp(n2n_sn_t * sss,
char buf[32];
struct sn_community *comm, *tmp;
uint64_t stamp;
const n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0}; /* 00:00:00:00:00:00 */
traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]",
udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)),
@ -804,6 +847,10 @@ static int process_udp(n2n_sn_t * sss,
int8_t allowed_match = -1;
uint8_t match = 0;
int match_length = 0;
n2n_ip_subnet_t ipaddr;
memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
/* Edge requesting registration with us. */
sss->stats.last_reg_super=now;
++(sss->stats.reg_super);
@ -869,6 +916,12 @@ static int process_udp(n2n_sn_t * sss,
memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t));
memcpy(ack.edgeMac, reg.edgeMac, sizeof(n2n_mac_t));
if ((reg.dev_addr.net_addr == 0) || (reg.dev_addr.net_addr == 0xFFFFFFFF) || (reg.dev_addr.net_bitlen == 0) ||
((reg.dev_addr.net_addr & 0xFFFF0000) == 0xA9FE0000 /* 169.254.0.0 */)) {
assign_one_ip_addr(sss, comm, &ipaddr);
ack.dev_addr.net_addr = ipaddr.net_addr;
ack.dev_addr.net_bitlen = ipaddr.net_bitlen;
}
ack.lifetime = reg_lifetime(sss);
ack.sock.family = AF_INET;
@ -876,13 +929,14 @@ static int process_udp(n2n_sn_t * sss,
memcpy(ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
ack.num_sn=0; /* No backup */
memset(&(ack.sn_bak), 0, sizeof(n2n_sock_t));
traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]",
macaddr_str(mac_buf, reg.edgeMac),
sock_to_cstr(sockbuf, &(ack.sock)));
update_edge(sss, reg.edgeMac, comm, &(ack.sock), now);
if(memcmp(reg.edgeMac, &null_mac, N2N_MAC_SIZE) != 0){
update_edge(sss, &reg, comm, &(ack.sock), now);
}
encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack);

View File

@ -289,130 +289,135 @@ int decode_REGISTER( n2n_REGISTER_t * reg,
return retval;
}
int encode_REGISTER_SUPER( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_SUPER_t * reg )
{
int retval=0;
retval += encode_common( base, idx, common );
retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE );
retval += encode_mac( base, idx, reg->edgeMac );
retval += encode_uint16( base, idx, 0 ); /* NULL auth scheme */
retval += encode_uint16( base, idx, 0 ); /* No auth data */
return retval;
int encode_REGISTER_SUPER(uint8_t *base,
size_t *idx,
const n2n_common_t *common,
const n2n_REGISTER_SUPER_t *reg) {
int retval = 0;
retval += encode_common(base, idx, common);
retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE);
retval += encode_mac(base, idx, reg->edgeMac);
retval += encode_uint32(base, idx, reg->dev_addr.net_addr);
retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen);
retval += encode_uint16(base, idx, 0); /* NULL auth scheme */
retval += encode_uint16(base, idx, 0); /* No auth data */
return retval;
}
int decode_REGISTER_SUPER( n2n_REGISTER_SUPER_t * reg,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t retval=0;
memset( reg, 0, sizeof(n2n_REGISTER_SUPER_t) );
retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx );
retval += decode_mac( reg->edgeMac, base, rem, idx );
retval += decode_uint16( &(reg->auth.scheme), base, rem, idx );
retval += decode_uint16( &(reg->auth.toksize), base, rem, idx );
retval += decode_buf( reg->auth.token, reg->auth.toksize, base, rem, idx );
return retval;
int decode_REGISTER_SUPER(n2n_REGISTER_SUPER_t *reg,
const n2n_common_t *cmn, /* info on how to interpret it */
const uint8_t *base,
size_t *rem,
size_t *idx) {
size_t retval = 0;
memset(reg, 0, sizeof(n2n_REGISTER_SUPER_t));
retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx);
retval += decode_mac(reg->edgeMac, base, rem, idx);
retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx);
retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx);
retval += decode_uint16(&(reg->auth.scheme), base, rem, idx);
retval += decode_uint16(&(reg->auth.toksize), base, rem, idx);
retval += decode_buf(reg->auth.token, reg->auth.toksize, base, rem, idx);
return retval;
}
int encode_REGISTER_ACK( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_ACK_t * reg )
{
int retval=0;
retval += encode_common( base, idx, common );
retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE );
retval += encode_mac( base, idx, reg->dstMac );
retval += encode_mac( base, idx, reg->srcMac );
/* The socket in REGISTER_ACK is the socket from which the REGISTER
* arrived. This is sent back to the sender so it knows what its public
* socket is. */
if ( 0 != reg->sock.family )
{
retval += encode_sock( base, idx, &(reg->sock) );
}
int encode_REGISTER_ACK(uint8_t *base,
size_t *idx,
const n2n_common_t *common,
const n2n_REGISTER_ACK_t *reg) {
int retval = 0;
retval += encode_common(base, idx, common);
retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE);
retval += encode_mac(base, idx, reg->dstMac);
retval += encode_mac(base, idx, reg->srcMac);
return retval;
/* The socket in REGISTER_ACK is the socket from which the REGISTER
* arrived. This is sent back to the sender so it knows what its public
* socket is. */
if (0 != reg->sock.family) {
retval += encode_sock(base, idx, &(reg->sock));
}
return retval;
}
int decode_REGISTER_ACK( n2n_REGISTER_ACK_t * reg,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t retval=0;
memset( reg, 0, sizeof(n2n_REGISTER_ACK_t) );
retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx );
retval += decode_mac( reg->dstMac, base, rem, idx );
retval += decode_mac( reg->srcMac, base, rem, idx );
/* The socket in REGISTER_ACK is the socket from which the REGISTER
* arrived. This is sent back to the sender so it knows what its public
* socket is. */
if ( cmn->flags & N2N_FLAGS_SOCKET )
{
retval += decode_sock( &(reg->sock), base, rem, idx );
}
int decode_REGISTER_ACK(n2n_REGISTER_ACK_t *reg,
const n2n_common_t *cmn, /* info on how to interpret it */
const uint8_t *base,
size_t *rem,
size_t *idx) {
size_t retval = 0;
memset(reg, 0, sizeof(n2n_REGISTER_ACK_t));
retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx);
retval += decode_mac(reg->dstMac, base, rem, idx);
retval += decode_mac(reg->srcMac, base, rem, idx);
return retval;
/* The socket in REGISTER_ACK is the socket from which the REGISTER
* arrived. This is sent back to the sender so it knows what its public
* socket is. */
if (cmn->flags & N2N_FLAGS_SOCKET) {
retval += decode_sock(&(reg->sock), base, rem, idx);
}
return retval;
}
int encode_REGISTER_SUPER_ACK( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_REGISTER_SUPER_ACK_t * reg )
{
int retval=0;
retval += encode_common( base, idx, common );
retval += encode_buf( base, idx, reg->cookie, N2N_COOKIE_SIZE );
retval += encode_mac( base, idx, reg->edgeMac );
retval += encode_uint16( base, idx, reg->lifetime );
retval += encode_sock( base, idx, &(reg->sock) );
retval += encode_uint8( base, idx, reg->num_sn );
if ( reg->num_sn > 0 )
{
/* We only support 0 or 1 at this stage */
retval += encode_sock( base, idx, &(reg->sn_bak) );
}
return retval;
int encode_REGISTER_SUPER_ACK(uint8_t *base,
size_t *idx,
const n2n_common_t *common,
const n2n_REGISTER_SUPER_ACK_t *reg) {
int retval = 0;
retval += encode_common(base, idx, common);
retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE);
retval += encode_mac(base, idx, reg->edgeMac);
retval += encode_uint32(base, idx, reg->dev_addr.net_addr);
retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen);
retval += encode_uint16(base, idx, reg->lifetime);
retval += encode_sock(base, idx, &(reg->sock));
retval += encode_uint8(base, idx, reg->num_sn);
if (reg->num_sn > 0) {
/* We only support 0 or 1 at this stage */
retval += encode_sock(base, idx, &(reg->sn_bak));
}
return retval;
}
int decode_REGISTER_SUPER_ACK( n2n_REGISTER_SUPER_ACK_t * reg,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t retval=0;
memset( reg, 0, sizeof(n2n_REGISTER_SUPER_ACK_t) );
retval += decode_buf( reg->cookie, N2N_COOKIE_SIZE, base, rem, idx );
retval += decode_mac( reg->edgeMac, base, rem, idx );
retval += decode_uint16( &(reg->lifetime), base, rem, idx );
int decode_REGISTER_SUPER_ACK(n2n_REGISTER_SUPER_ACK_t *reg,
const n2n_common_t *cmn, /* info on how to interpret it */
const uint8_t *base,
size_t *rem,
size_t *idx) {
size_t retval = 0;
/* Socket is mandatory in this message type */
retval += decode_sock( &(reg->sock), base, rem, idx );
memset(reg, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx);
retval += decode_mac(reg->edgeMac, base, rem, idx);
retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx);
retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx);
retval += decode_uint16(&(reg->lifetime), base, rem, idx);
/* Following the edge socket are an array of backup supernodes. */
retval += decode_uint8( &(reg->num_sn), base, rem, idx );
if ( reg->num_sn > 0 )
{
/* We only support 0 or 1 at this stage */
retval += decode_sock( &(reg->sn_bak), base, rem, idx );
}
/* Socket is mandatory in this message type */
retval += decode_sock(&(reg->sock), base, rem, idx);
return retval;
/* Following the edge socket are an array of backup supernodes. */
retval += decode_uint8(&(reg->num_sn), base, rem, idx);
if (reg->num_sn > 0) {
/* We only support 0 or 1 at this stage */
retval += decode_sock(&(reg->sn_bak), base, rem, idx);
}
return retval;
}
int fill_sockaddr( struct sockaddr * addr,
size_t addrlen,
const n2n_sock_t * sock )
@ -475,35 +480,36 @@ int decode_PACKET( n2n_PACKET_t * pkt,
return retval;
}
int encode_PEER_INFO( uint8_t * base,
size_t * idx,
const n2n_common_t * common,
const n2n_PEER_INFO_t * pkt )
{
int retval=0;
retval += encode_common( base, idx, common );
retval += encode_uint16( base, idx, pkt->aflags );
retval += encode_mac( base, idx, pkt->mac );
retval += encode_sock( base, idx, &pkt->sock );
return retval;
int encode_PEER_INFO(uint8_t *base,
size_t *idx,
const n2n_common_t *common,
const n2n_PEER_INFO_t *pkt) {
int retval = 0;
retval += encode_common(base, idx, common);
retval += encode_uint16(base, idx, pkt->aflags);
retval += encode_mac(base, idx, pkt->mac);
retval += encode_sock(base, idx, &pkt->sock);
return retval;
}
int decode_PEER_INFO( n2n_PEER_INFO_t * pkt,
const n2n_common_t * cmn, /* info on how to interpret it */
const uint8_t * base,
size_t * rem,
size_t * idx )
{
size_t retval=0;
memset( pkt, 0, sizeof(n2n_PEER_INFO_t) );
retval += decode_uint16( &(pkt->aflags), base, rem, idx );
retval += decode_mac( pkt->mac, base, rem, idx );
retval += decode_sock( &pkt->sock, base, rem, idx );
return retval;
int decode_PEER_INFO(n2n_PEER_INFO_t *pkt,
const n2n_common_t *cmn, /* info on how to interpret it */
const uint8_t *base,
size_t *rem,
size_t *idx) {
size_t retval = 0;
memset(pkt, 0, sizeof(n2n_PEER_INFO_t));
retval += decode_uint16(&(pkt->aflags), base, rem, idx);
retval += decode_mac(pkt->mac, base, rem, idx);
retval += decode_sock(&pkt->sock, base, rem, idx);
return retval;
}
int encode_QUERY_PEER( uint8_t * base,
size_t * idx,
const n2n_common_t * common,

View File

@ -98,13 +98,14 @@ struct ip {
/* ************************************* */
typedef struct tuntap_dev {
HANDLE device_handle;
char *device_name;
char *ifName;
OVERLAPPED overlap_read, overlap_write;
uint8_t mac_addr[6];
uint32_t ip_addr, device_mask;
unsigned int mtu;
HANDLE device_handle;
char *device_name;
char *ifName;
OVERLAPPED overlap_read, overlap_write;
n2n_mac_t mac_addr;
uint32_t ip_addr;
uint32_t device_mask;
unsigned int mtu;
} tuntap_dev;
#define index(a, b) strchr(a, b)

View File

@ -1,8 +1,15 @@
/* winconfig.h. Win32 replacement for file generated from config.h.in by configure. */
/* OS name */
#ifndef PACKAGE_OSNAME
#define PACKAGE_OSNAME N2N_OSNAME
#endif
/* Define to the version of this package. */
#ifndef PACKAGE_VERSION
#define PACKAGE_VERSION N2N_VERSION
#endif
#ifndef GIT_RELEASE
#define GIT_RELEASE N2N_VERSION
#endif