support linux l2 bridge (#1044)

* support linux l2 bridge

* unified timeout name

* typo

* minor code style adaptions

* feature define

* feature define

* feature define

* feature define

* added hint to bridging to help output

* added hint to bridging

* drafted bridging documentation

* added bridging hint

---------

Co-authored-by: Logan oos Even <46396513+Logan007@users.noreply.github.com>
This commit is contained in:
Dylan Yee 2023-05-04 11:00:38 +08:00 committed by GitHub
parent 39b9c6b1c0
commit e01daf4a85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 105 additions and 6 deletions

View File

@ -31,10 +31,12 @@ It is available a special community which provides interconnection between super
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
## Bridging and 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 by temporarily modifying the routing table (`tools/n2n-route`). Details can be found in the [Routing document](Routing.md).
Also, n2n supports [Bridging](Bridging.md) of LANs, e.g. to connect otherwise un-connected LANs by an encrypted n2n tunnel on level 2.
## Traffic Restrictions

27
doc/Bridging.md Normal file
View File

@ -0,0 +1,27 @@
# Bridging (Linux)
## General Remarks
`edge`s can be part of network bridges. As such, n2n can connect otherwise un-connected LANs.
## How To Use with `brctl`
... requires `-r`
... general syntax
... one example connecting two remote sites' LANs, including commands
## How it works
... remembers peer info MAC
... ageing
... internal MAC replaced inside usually encrypted packet data (no disclosure then)
... initial learning
## Broadcasts
... note on broadcast domain
## Compile Time Option
The `-r`option at edge does not differentiate between the use cases _routing_ and _bridging_. In case the MAC-learning and MAC-replacing bridging code
interfers with some special routing scenario, removal of the `#define HAVE_BRIDGING_SUPPORT` from `/include/n2n.h` file disables it at compile time.

3
edge.8
View File

@ -132,7 +132,8 @@ specify n2n MTU of TAP interface, default 1290
\fB\-r\fR
enable IP packet forwarding/routing through the n2n virtual LAN. Without this
option, IP packets arriving over n2n are dropped if not for the -a <addr> (or
DHCP assigned) IP address of the edge interface.
DHCP assigned) IP address of the edge interface. This option is also required
to allow n2n device being used in network bridging, e.g. with brctl.
.TP
\fB\-E\fR
accept packets destined for multicast ethernet MAC addresses. These addresses

View File

@ -35,6 +35,7 @@
#define N2N_HAVE_DAEMON /* needs to be defined before it gets undefined */
#define N2N_HAVE_TCP /* needs to be defined before it gets undefined */
#define HAVE_BRIDGING_SUPPORT
/* #define N2N_CAN_NAME_IFACE */

View File

@ -51,7 +51,9 @@
#define REGISTER_SUPER_INTERVAL_DFL 20 /* sec, usually UDP NAT entries in a firewall expire after 30 seconds */
#define SWEEP_TIME 30 /* sec, indicates the value after which we have to sort the hash list of supernodes in edges
* and when we send out packets to query selection-relevant informations from supernodes. */
#ifdef HAVE_BRIDGING_SUPPORT
#define HOSTINFO_TIMEOUT 300 /* sec, how long after last seen will the hostinfo be deleted */
#endif
#define NUMBER_SN_PINGS_INITIAL 15 /* number of supernodes to concurrently ping during bootstrap and immediately afterwards */
#define NUMBER_SN_PINGS_REGULAR 5 /* number of supernodes to concurrently ping during regular edge operation */

View File

@ -470,6 +470,15 @@ struct peer_info {
typedef struct peer_info peer_info_t;
#ifdef HAVE_BRIDGING_SUPPORT
struct host_info {
n2n_mac_t mac_addr;
n2n_mac_t edge_addr;
time_t last_seen;
UT_hash_handle hh; /* makes this structure hashable */
};
#endif
typedef struct n2n_edge n2n_edge_t;
/* *************************************************** */
@ -723,8 +732,10 @@ struct n2n_edge {
/* Peers */
struct peer_info * known_peers; /**< Edges we are connected to. */
struct peer_info * pending_peers; /**< Edges we have tried to register with. */
/* Timers */
#ifdef HAVE_BRIDGING_SUPPORT
struct host_info * known_hosts; /**< hosts we know. */
#endif
/* 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. */

View File

@ -306,7 +306,8 @@ static void help (int level) {
printf(" -d <device> | TAP device name\n");
#endif
printf(" -M <mtu> | specify n2n MTU of TAP interface, default %d\n", DEFAULT_MTU);
printf(" -r | enable packet forwarding through n2n community\n");
printf(" -r | enable packet forwarding through n2n community,\n"
" | also required for bridging\n");
printf(" -E | accept multicast MAC addresses, drop by default\n");
printf(" -I <description> | annotate the edge's description used for easier\n"
" | identification in management port output or username\n");

View File

@ -1763,6 +1763,24 @@ static int handle_PACKET (n2n_edge_t * eee,
}
}
#ifdef HAVE_BRIDGING_SUPPORT
if((eee->conf.allow_routing) && (!is_multi_broadcast(eh->shost))) {
struct host_info *host = NULL;
HASH_FIND(hh, eee->known_hosts, eh->shost, sizeof(n2n_mac_t), host);
if(host == NULL) {
struct host_info *host = calloc(1, sizeof(struct host_info));
memcpy(host->mac_addr, eh->shost, sizeof(n2n_mac_t));
memcpy(host->edge_addr, pkt->srcMac, sizeof(n2n_mac_t));
host->last_seen = now;
HASH_ADD(hh, eee->known_hosts, mac_addr, sizeof(n2n_mac_t), host);
} else {
memcpy(host->edge_addr, pkt->srcMac, sizeof(n2n_mac_t));
host->last_seen = now;
}
}
#endif
if(eee->network_traffic_filter->filter_packet_from_peer(eee->network_traffic_filter, eee, orig_sender,
eth_payload, eth_size) == N2N_DROP) {
traceEvent(TRACE_DEBUG, "filtered packet of size %u", (unsigned int)eth_size);
@ -2014,6 +2032,16 @@ void edge_send_packet2net (n2n_edge_t * eee,
/* Once processed, send to destination in PACKET */
memcpy(destMac, tap_pkt, N2N_MAC_SIZE); /* dest MAC is first in ethernet header */
#ifdef HAVE_BRIDGING_SUPPORT
/* find the destMac behind which edge, and change dest to this edge */
if((eee->conf.allow_routing) && (!is_multi_broadcast(destMac))) {
struct host_info *host = NULL;
HASH_FIND(hh, eee->known_hosts, destMac, sizeof(n2n_mac_t), host);
if(host) {
memcpy(destMac, host->edge_addr, N2N_MAC_SIZE);
}
}
#endif
memset(&cmn, 0, sizeof(cmn));
cmn.ttl = N2N_DEFAULT_TTL;
@ -2821,6 +2849,9 @@ int run_edge_loop (n2n_edge_t *eee) {
time_t lastTransop = 0;
time_t last_purge_known = 0;
time_t last_purge_pending = 0;
#ifdef HAVE_BRIDGING_SUPPORT
time_t last_purge_host = 0;
#endif
uint16_t expected = sizeof(uint16_t);
uint16_t position = 0;
@ -2956,6 +2987,19 @@ int run_edge_loop (n2n_edge_t *eee) {
HASH_COUNT(eee->known_peers));
}
#ifdef HAVE_BRIDGING_SUPPORT
if((eee->conf.allow_routing) && (now > last_purge_host + SWEEP_TIME)) {
struct host_info *host, *host_tmp;
HASH_ITER(hh, eee->known_hosts, host, host_tmp) {
if(now > host->last_seen + HOSTINFO_TIMEOUT) {
HASH_DEL(eee->known_hosts, host);
free(host);
}
}
last_purge_host = now;
}
#endif
if((eee->conf.tuntap_ip_mode == TUNTAP_IP_MODE_DHCP) &&
((now - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) {
uint32_t old_ip = eee->device.ip_addr;
@ -3010,6 +3054,16 @@ void edge_term (n2n_edge_t * eee) {
clear_peer_list(&eee->known_peers);
clear_peer_list(&eee->conf.supernodes);
#ifdef HAVE_BRIDGING_SUPPORT
if(eee->conf.allow_routing) {
struct host_info *host, *host_tmp;
HASH_ITER(hh, eee->known_hosts, host, host_tmp) {
HASH_DEL(eee->known_hosts, host);
free(host);
}
}
#endif
eee->transop.deinit(&eee->transop);
eee->transop_lzo.deinit(&eee->transop_lzo);
#ifdef HAVE_ZSTD