let auto ip feature handle several sub-networks

This commit is contained in:
Logan007 2020-08-18 22:35:27 +05:45
parent aab94e9a82
commit 78409df1c8
7 changed files with 208 additions and 43 deletions

View File

@ -35,3 +35,31 @@ ntop[0-1][0-9]
# '\d' Digits, [0-9]
# '\D' Non-digits
#
# fixed-name communities can optionally be followed by a network using the
# network/bitlen syntax such as the following line
#
home 192.168.1.0/24
#
# the supernode draws ip addresses to assign to the edges (if they omit the `-a`
# parameter) from this network. note that the network is delimited by [SPACE] so
# community names cannot contain a [SPACE] either.
#
# if no network is provided here, the supernode assigns some other network to each
# community. networks are taken from the default range 10.128.0.0 - 10.255.255.0/24
# as long as no other network rane is provided through the supernode's command line
# option `-d`. those sub-networks are distinct so several edges with different
# communities can be used at the same computer (being served ip addresses from the
# same supernode). also, the networks described in this file are avoided.
#
# however, all networks assigned in this file are not checked for colliding ranges
# so different communities can use same or overlapping sub-networks. that does not
# impose a problem if the communities do not share edge nodes.
#
# there seems to be no sense in pre-assigning sub-networks to communities whose
# names are defined by regular expressions. those will be assigned a sub-network
# from the default range or the `-d` range.
#
# if `-a` is used with the edge, the edge uses the ip address specified with the
# `-a xxx.xxx.xxx.xxx` option. also, the enhanced syntax `-r -a dhcp:0.0.0.0` is
# still available to serve more professional needs by a dhcp server.
#

View File

@ -370,6 +370,7 @@ struct sn_community
he_context_t *header_iv_ctx; /* Header IV ecnryption cipher context, REMOVE as soon as seperate fields for checksum and replay protection available */
struct peer_info *edges; /* Link list of registered edges. */
int64_t number_enc_packets; /* Number of encrypted packets handled so far, required for sorting from time to time */
n2n_ip_subnet_t dhcp_net; /* Address range of dhcp service. */
UT_hash_handle hh; /* makes this structure hashable */
};
@ -390,7 +391,8 @@ typedef struct n2n_sn
uint16_t mport; /* Management UDP port to bind to. */
int sock; /* Main socket for UDP traffic with edges. */
int mgmt_sock; /* management socket. */
n2n_ip_subnet_t dhcp_addr; /* Address range of dhcp service. */
n2n_ip_subnet_t min_dhcp_net; /* Address range of dhcp service. */
n2n_ip_subnet_t max_dhcp_net; /* Address range of dhcp service. */
#ifndef WIN32
uid_t userid;
gid_t groupid;
@ -502,6 +504,7 @@ int quick_edge_init(char *device_name, char *community_name,
int sn_init(n2n_sn_t *sss);
void sn_term(n2n_sn_t *sss);
int run_sn_loop(n2n_sn_t *sss, int *keep_running);
int assign_one_ip_subnet(n2n_sn_t *sss, struct sn_community *comm);
const char* compression_str(uint8_t cmpr);
const char* transop_str(enum n2n_transform tr);

View File

@ -102,7 +102,8 @@
#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_MIN_DHCP_NET_DEFAULT "10.128.0.0"
#define N2N_SN_MAX_DHCP_NET_DEFAULT "10.255.255.0"
#define N2N_SN_DHCP_NET_BIT_DEFAULT 24
/* ************************************** */

View File

@ -20,6 +20,8 @@ void pearson_hash_256 (uint8_t *out, const uint8_t *in, size_t len);
void pearson_hash_128 (uint8_t *out, const uint8_t *in, size_t len);
uint32_t pearson_hash_32 (const uint8_t *in, size_t len);
uint16_t pearson_hash_16 (const uint8_t *in, size_t len);
void pearson_hash_init();

View File

@ -270,7 +270,7 @@ void pearson_hash_128 (uint8_t *out, const uint8_t *in, size_t len) {
*o = lower_hash;
}
/* --- for later use ---
// 32-bit hash: the return value has to be interpreted as uint32_t and
// follows machine-specific endianess in memory
uint32_t pearson_hash_32 (const uint8_t *in, size_t len) {
@ -300,7 +300,7 @@ uint32_t pearson_hash_32 (const uint8_t *in, size_t len) {
}
// output
return hash;
} --- pearson_hash_32 for later use --- */
}
// 16-bit hash: the return value has to be interpreted as uint16_t and

View File

@ -27,12 +27,17 @@ static n2n_sn_t sss_node;
*
*/
static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
char buffer[4096], *line;
char buffer[4096], *line, *cmn_str, net_str[20];
dec_ip_str_t ip_str = {'\0'};
uint8_t bitlen;
in_addr_t net;
uint32_t mask;
FILE *fd = fopen(path, "r");
struct sn_community *s, *tmp;
uint32_t num_communities = 0;
struct sn_community_regular_expression *re, *tmp_re;
uint32_t num_regex = 0;
int has_net;
if(fd == NULL) {
traceEvent(TRACE_WARNING, "File %s not found", path);
@ -66,15 +71,20 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
break;
}
// cut off any IP sub-network upfront
cmn_str = (char*)calloc(len+1, sizeof(char));
has_net = ( sscanf (line, "%s %s", cmn_str, net_str) == 2 );
// if it contains typical characters...
if(NULL != strpbrk(line, ".^$*+?[]\\")) {
if(NULL != strpbrk(cmn_str, ".^$*+?[]\\")) {
// ...it is treated as regular expression
re = (struct sn_community_regular_expression*)calloc(1,sizeof(struct sn_community_regular_expression));
if (re) {
re->rule = re_compile(line);
re->rule = re_compile(cmn_str);
HASH_ADD_PTR(sss->rules, rule, re);
num_regex++;
traceEvent(TRACE_INFO, "Added regular expression for allowed communities '%s'", line);
traceEvent(TRACE_INFO, "Added regular expression for allowed communities '%s'", cmn_str);
free(cmn_str);
continue;
}
}
@ -82,7 +92,7 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
s = (struct sn_community*)calloc(1,sizeof(struct sn_community));
if(s != NULL) {
strncpy((char*)s->community, line, N2N_COMMUNITY_SIZE-1);
strncpy((char*)s->community, cmn_str, N2N_COMMUNITY_SIZE-1);
s->community[N2N_COMMUNITY_SIZE-1] = '\0';
/* loaded from file, this community is unpurgeable */
s->purgeable = COMMUNITY_UNPURGEABLE;
@ -95,7 +105,42 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
num_communities++;
traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]",
(char*)s->community, num_communities);
// check for sub-network address
if(has_net) {
if(sscanf(net_str, "%15[^/]/%hhu", ip_str, &bitlen) != 2) {
traceEvent(TRACE_WARNING, "Bad net/bit format '%s' for community '%c', ignoring. See comments inside community.list file.",
net_str, cmn_str);
has_net = 0;
}
net = inet_addr(ip_str);
mask = bitlen2mask(bitlen);
if((net == (in_addr_t)(-1)) || (net == INADDR_NONE) || (net == INADDR_ANY)
|| ((ntohl(net) & ~mask) != 0) ) {
traceEvent(TRACE_WARNING, "Bad network '%s/%u' in '%s' for community '%s', ignoring.",
ip_str, bitlen, net_str, cmn_str);
has_net = 0;
}
if ((bitlen > 30) || (bitlen == 0)) {
traceEvent(TRACE_WARNING, "Bad prefix '%hhu' in '%s' for community '%s', ignoring.",
bitlen, net_str, cmn_str);
has_net = 0;
}
}
if(has_net) {
s->dhcp_net.net_addr = ntohl(net);
s->dhcp_net.net_bitlen = bitlen;
traceEvent(TRACE_INFO, "Assigned sub-network %s/%u to community '%s'.",
inet_ntoa(*(struct in_addr *) &net),
s->dhcp_net.net_bitlen,
s->community);
} else {
assign_one_ip_subnet(sss, s);
}
}
free(cmn_str);
}
fclose(fd);
@ -138,7 +183,7 @@ static void help() {
printf("[-u <uid> -g <gid>] ");
#endif /* ifndef WIN32 */
printf("[-t <mgmt port>] ");
printf("[-d <net/bit>] ");
printf("[-d <net-net/bit>] ");
printf("[-v] ");
printf("\n\n");
@ -152,7 +197,7 @@ static void help() {
printf("-g <GID> | Group ID (numeric) to use when privileges are dropped.\n");
#endif /* ifndef WIN32 */
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("-d <net-net/bit> | Subnet range for community ip address service for edges. eg. -d 10.128.255.0-10.255.255.0/24\n");
printf("-v | Increase verbosity. Can be used multiple times.\n");
printf("-h | This help message.\n");
printf("\n");
@ -175,34 +220,43 @@ static int setOption(int optkey, char *_optarg, n2n_sn_t *sss) {
break;
case 'd': {
dec_ip_str_t ip_str = {'\0'};
in_addr_t net;
dec_ip_str_t ip_min_str = {'\0'};
dec_ip_str_t ip_max_str = {'\0'};
in_addr_t net_min, net_max;
uint8_t bitlen;
uint32_t mask;
if (sscanf(_optarg, "%15[^/]/%hhu", ip_str, &bitlen) != 2) {
traceEvent(TRACE_WARNING, "Bad net/bit format '%s'. See -h.", _optarg);
if (sscanf(_optarg, "%15[^\\-]-%15[^/]/%hhu", ip_min_str, ip_max_str, &bitlen) != 3) {
traceEvent(TRACE_WARNING, "Bad net-net/bit format '%s'. See -h.", _optarg);
break;
}
net = inet_addr(ip_str);
if ((net == (in_addr_t)(-1)) || (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);
net_min = inet_addr(ip_min_str);
net_max = inet_addr(ip_max_str);
mask = bitlen2mask(bitlen);
if ((net_min == (in_addr_t)(-1)) || (net_min == INADDR_NONE) || (net_min == INADDR_ANY)
|| (net_max == (in_addr_t)(-1)) || (net_max == INADDR_NONE) || (net_max == INADDR_ANY)
|| (ntohl(net_min) > ntohl(net_max))
|| ((ntohl(net_min) & ~mask) != 0) || ((ntohl(net_max) & ~mask) != 0) ) {
traceEvent(TRACE_WARNING, "Bad network range '%s...%s/%u' in '%s', defaulting to '%s...%s/%d'",
ip_min_str, ip_max_str, bitlen, _optarg,
N2N_SN_MIN_DHCP_NET_DEFAULT, N2N_SN_MAX_DHCP_NET_DEFAULT, N2N_SN_DHCP_NET_BIT_DEFAULT);
break;
}
if (bitlen > 32) {
traceEvent(TRACE_WARNING, "Bad prefix '%hhu' in '%s', Use default: '%s/%d'",
if ((bitlen > 30) || (bitlen == 0)) {
traceEvent(TRACE_WARNING, "Bad prefix '%hhu' in '%s', defaulting to '%s...%s/%d'",
bitlen, _optarg,
N2N_SN_DHCP_NET_ADDR_DEFAULT, N2N_SN_DHCP_NET_BIT_DEFAULT);
N2N_SN_MIN_DHCP_NET_DEFAULT, N2N_SN_MAX_DHCP_NET_DEFAULT, N2N_SN_DHCP_NET_BIT_DEFAULT);
break;
}
traceEvent(TRACE_NORMAL, "The subnet of DHCP service is: '%s/%hhu'.", ip_str, bitlen);
traceEvent(TRACE_NORMAL, "The network range for community ip address service is '%s...%s/%hhu'.", ip_min_str, ip_max_str, bitlen);
sss->dhcp_addr.net_addr = ntohl(net);
sss->dhcp_addr.net_bitlen = bitlen;
sss->min_dhcp_net.net_addr = ntohl(net_min);
sss->min_dhcp_net.net_bitlen = bitlen;
sss->max_dhcp_net.net_addr = ntohl(net_max);
sss->max_dhcp_net.net_bitlen = bitlen;
break;
}

View File

@ -218,9 +218,12 @@ int sn_init(n2n_sn_t *sss) {
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;
sss->min_dhcp_net.net_addr = inet_addr(N2N_SN_MIN_DHCP_NET_DEFAULT);
sss->min_dhcp_net.net_addr = ntohl(sss->min_dhcp_net.net_addr);
sss->min_dhcp_net.net_bitlen = N2N_SN_DHCP_NET_BIT_DEFAULT;
sss->max_dhcp_net.net_addr = inet_addr(N2N_SN_MAX_DHCP_NET_DEFAULT);
sss->max_dhcp_net.net_addr = ntohl(sss->max_dhcp_net.net_addr);
sss->max_dhcp_net.net_bitlen = N2N_SN_DHCP_NET_BIT_DEFAULT;
return 0; /* OK */
}
@ -335,15 +338,14 @@ static signed int peer_tap_ip_sort(struct peer_info *a, struct peer_info *b) {
/** 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,
static int assign_one_ip_addr(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;
mask = bitlen2mask(comm->dhcp_net.net_bitlen);
net_id = comm->dhcp_net.net_addr & mask;
max_host = ~mask;
HASH_SORT(comm->edges, peer_tap_ip_sort);
@ -364,13 +366,87 @@ static int assign_one_ip_addr(n2n_sn_t *sss,
}
}
ipaddr->net_addr = net_id | host_id;
ipaddr->net_bitlen = sss->dhcp_addr.net_bitlen;
ipaddr->net_bitlen = comm->dhcp_net.net_bitlen;
traceEvent(TRACE_INFO, "Assign IP %s to tap adapter of edge.", ip_subnet_to_str(ip_bit_str, ipaddr));
return 0;
}
/** checks if a certain sub-network is still available, i.e. does not cut any other community's sub-network */
int subnet_available(n2n_sn_t *sss,
struct sn_community *comm,
uint32_t net_id,
uint32_t mask) {
struct sn_community *cmn, *tmpCmn;
int success = 1;
HASH_ITER(hh, sss->communities, cmn, tmpCmn) {
if (cmn == comm) continue;
if( (net_id <= (cmn->dhcp_net.net_addr + ~bitlen2mask(cmn->dhcp_net.net_bitlen)))
&&(net_id + ~mask >= cmn->dhcp_net.net_addr) ) {
success = 0;
break;
}
}
return success;
}
/** The IP address assigned to the edge by the DHCP function of sn. */
int assign_one_ip_subnet(n2n_sn_t *sss,
struct sn_community *comm) {
uint32_t net_id, net_id_i, mask, net_increment;
uint32_t no_subnets;
uint8_t success;
in_addr_t net;
mask = bitlen2mask(sss->min_dhcp_net.net_bitlen);
// number of possible sub-networks
no_subnets = (sss->max_dhcp_net.net_addr - sss->min_dhcp_net.net_addr);
no_subnets >>= (32 - sss->min_dhcp_net.net_bitlen);
no_subnets += 1;
// proposal for sub-network to choose
net_id = pearson_hash_32(comm->community, N2N_COMMUNITY_SIZE) % no_subnets;
net_id = sss->min_dhcp_net.net_addr + (net_id << (32 - sss->min_dhcp_net.net_bitlen));
// check for availability starting from net_id, then downwards, ...
net_increment = (~mask+1);
for(net_id_i=net_id; net_id_i >= sss->min_dhcp_net.net_addr; net_id_i -= net_increment) {
success = subnet_available(sss, comm, net_id_i, mask);
if(success) break;
}
// ... then upwards
if(!success) {
for(net_id_i=net_id + net_increment; net_id_i <= sss->max_dhcp_net.net_addr; net_id_i += net_increment) {
success = subnet_available(sss, comm, net_id_i, mask);
if(success) break;
}
}
if(success) {
comm->dhcp_net.net_addr = net_id_i;
comm->dhcp_net.net_bitlen = sss->min_dhcp_net.net_bitlen;
net = htonl(comm->dhcp_net.net_addr);
traceEvent(TRACE_INFO, "Assigned sub-network %s/%u to community '%s'.",
inet_ntoa(*(struct in_addr *) &net),
comm->dhcp_net.net_bitlen,
comm->community);
return 0;
} else {
comm->dhcp_net.net_addr = 0;
comm->dhcp_net.net_bitlen = 0;
traceEvent(TRACE_WARNING, "No assignable sub-network left for community '%s'.",
comm->community);
return -1;
}
}
/***
*
* For a given packet, find the apporopriate internal last valid time stamp for lookup
@ -905,6 +981,7 @@ static int process_udp(n2n_sn_t * sss,
HASH_ADD_STR(sss->communities, community, comm);
traceEvent(TRACE_INFO, "New community: %s", comm->community);
assign_one_ip_subnet(sss, comm);
}
}
@ -918,7 +995,7 @@ static int process_udp(n2n_sn_t * sss,
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);
assign_one_ip_addr(comm, &ipaddr);
ack.dev_addr.net_addr = ipaddr.net_addr;
ack.dev_addr.net_bitlen = ipaddr.net_bitlen;
}