mirror of
https://github.com/ntop/n2n.git
synced 2024-09-20 00:51:10 +02:00
added 'reload_communities' command to supernode management port (#740)
This commit is contained in:
parent
fe4dfc5a7a
commit
c35129b8e2
|
@ -29,6 +29,7 @@
|
||||||
#define MSG_TYPE_PEER_INFO 10
|
#define MSG_TYPE_PEER_INFO 10
|
||||||
#define MSG_TYPE_QUERY_PEER 11
|
#define MSG_TYPE_QUERY_PEER 11
|
||||||
#define MSG_TYPE_MAX_TYPE 11
|
#define MSG_TYPE_MAX_TYPE 11
|
||||||
|
#define MSG_TYPE_RE_REGISTER_SUPER 12
|
||||||
|
|
||||||
/* Max available space to add supernodes' informations (sockets and MACs) in REGISTER_SUPER_ACK
|
/* Max available space to add supernodes' informations (sockets and MACs) in REGISTER_SUPER_ACK
|
||||||
* Field sizes of REGISTER_SUPER_ACK as used in encode/decode fucntions in src/wire.c
|
* Field sizes of REGISTER_SUPER_ACK as used in encode/decode fucntions in src/wire.c
|
||||||
|
|
|
@ -254,7 +254,8 @@ typedef enum n2n_pc {
|
||||||
n2n_register_super_nak = 8, /* NAK from supernode to edge - registration refused */
|
n2n_register_super_nak = 8, /* NAK from supernode to edge - registration refused */
|
||||||
n2n_federation = 9, /* Not used by edge */
|
n2n_federation = 9, /* Not used by edge */
|
||||||
n2n_peer_info = 10, /* Send info on a peer from sn to edge */
|
n2n_peer_info = 10, /* Send info on a peer from sn to edge */
|
||||||
n2n_query_peer = 11 /* ask supernode for info on a peer */
|
n2n_query_peer = 11, /* ask supernode for info on a peer */
|
||||||
|
n2n_re_register_super = 12 /* ask edge to re-register with supernode */
|
||||||
} n2n_pc_t;
|
} n2n_pc_t;
|
||||||
|
|
||||||
#define N2N_FLAGS_OPTIONS 0x0080
|
#define N2N_FLAGS_OPTIONS 0x0080
|
||||||
|
|
|
@ -2722,6 +2722,30 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MSG_TYPE_RE_REGISTER_SUPER: {
|
||||||
|
|
||||||
|
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
||||||
|
if(!find_peer_time_stamp_and_verify(eee, sn, null_mac, stamp, TIME_STAMP_NO_JITTER)) {
|
||||||
|
traceEvent(TRACE_DEBUG, "readFromIPSocket dropped RE_REGISTER due to time stamp error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// only accept in user/pw mode for immediate re-registration because the new
|
||||||
|
// key is required for continous traffic flow, in other modes edge will realize
|
||||||
|
// changes with regular recurring REGISTER_SUPER
|
||||||
|
if(!eee->conf.shared_secret) {
|
||||||
|
traceEvent(TRACE_DEBUG, "readFromIPScoket dropped RE_REGISTER_SUPER as not in user/pw auth mode.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
traceEvent(TRACE_INFO, "Rx RE_REGISTER_SUPER");
|
||||||
|
|
||||||
|
eee->sn_wait = 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Not a known message type */
|
/* Not a known message type */
|
||||||
traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type);
|
traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type);
|
||||||
|
|
241
src/sn.c
241
src/sn.c
|
@ -25,226 +25,11 @@
|
||||||
|
|
||||||
static n2n_sn_t sss_node;
|
static n2n_sn_t sss_node;
|
||||||
|
|
||||||
|
void close_tcp_connection (n2n_sn_t *sss, n2n_tcp_connection_t *conn);
|
||||||
|
void calculate_shared_secrets (n2n_sn_t *sss);
|
||||||
|
int load_allowed_sn_community (n2n_sn_t *sss);
|
||||||
int resolve_create_thread (n2n_resolve_parameter_t **param, struct peer_info *sn_list);
|
int resolve_create_thread (n2n_resolve_parameter_t **param, struct peer_info *sn_list);
|
||||||
|
|
||||||
/** Load the list of allowed communities. Existing/previous ones will be removed
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static int load_allowed_sn_community (n2n_sn_t *sss) {
|
|
||||||
|
|
||||||
char buffer[4096], *line, *cmn_str, net_str[20], format[20];
|
|
||||||
|
|
||||||
sn_user_t *user, *tmp_user;
|
|
||||||
n2n_desc_t username;
|
|
||||||
n2n_private_public_key_t public_key;
|
|
||||||
uint8_t ascii_public_key[(N2N_PRIVATE_PUBLIC_KEY_SIZE * 8 + 5) / 6 + 1];
|
|
||||||
|
|
||||||
dec_ip_str_t ip_str = {'\0'};
|
|
||||||
uint8_t bitlen;
|
|
||||||
in_addr_t net;
|
|
||||||
uint32_t mask;
|
|
||||||
FILE *fd = fopen(sss->community_file, "r");
|
|
||||||
struct sn_community *comm, *tmp_comm, *last_added_comm = NULL;
|
|
||||||
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", sss->community_file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove communities (not: federation)
|
|
||||||
HASH_ITER(hh, sss->communities, comm, tmp_comm) {
|
|
||||||
if(comm->is_federation) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove allowed users from community
|
|
||||||
HASH_ITER(hh, comm->allowed_users, user, tmp_user) {
|
|
||||||
free(user->shared_secret_ctx);
|
|
||||||
HASH_DEL(comm->allowed_users, user);
|
|
||||||
free(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove community
|
|
||||||
HASH_DEL(sss->communities, comm);
|
|
||||||
if(NULL != comm->header_encryption_ctx_static) {
|
|
||||||
// remove header encryption keys
|
|
||||||
free(comm->header_encryption_ctx_static);
|
|
||||||
free(comm->header_encryption_ctx_dynamic);
|
|
||||||
}
|
|
||||||
free(comm);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove all regular expressions for allowed communities
|
|
||||||
HASH_ITER(hh, sss->rules, re, tmp_re) {
|
|
||||||
HASH_DEL(sss->rules, re);
|
|
||||||
free(re);
|
|
||||||
}
|
|
||||||
|
|
||||||
// format definition for possible user-key entries
|
|
||||||
sprintf(format, "%c %%%ds %%%ds", N2N_USER_KEY_LINE_STARTER, N2N_DESC_SIZE - 1, sizeof(ascii_public_key)-1);
|
|
||||||
|
|
||||||
while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) {
|
|
||||||
int len = strlen(line);
|
|
||||||
|
|
||||||
if((len < 2) || line[0] == '#') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
len--;
|
|
||||||
while(len > 0) {
|
|
||||||
if((line[len] == '\n') || (line[len] == '\r')) {
|
|
||||||
line[len] = '\0';
|
|
||||||
len--;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// the loop above does not always determine correct 'len'
|
|
||||||
len = strlen(line);
|
|
||||||
|
|
||||||
// user-key line for edge authentication?
|
|
||||||
if(line[0] == N2N_USER_KEY_LINE_STARTER) { /* special first character */
|
|
||||||
if(sscanf(line, format, username, ascii_public_key) == 2) { /* correct format */
|
|
||||||
if(last_added_comm) { /* is there a valid community to add users to */
|
|
||||||
user = (sn_user_t*)calloc(1, sizeof(sn_user_t));
|
|
||||||
if(user) {
|
|
||||||
// username
|
|
||||||
memcpy(user->name, username, sizeof(username));
|
|
||||||
// public key
|
|
||||||
ascii_to_bin(public_key, ascii_public_key);
|
|
||||||
memcpy(user->public_key, public_key, sizeof(public_key));
|
|
||||||
// common shared secret will be calculated later
|
|
||||||
// add to list
|
|
||||||
HASH_ADD(hh, last_added_comm->allowed_users, public_key, sizeof(n2n_private_public_key_t), user);
|
|
||||||
traceEvent(TRACE_INFO, "Added user '%s' with public key '%s' to community '%s'",
|
|
||||||
user->name, ascii_public_key, last_added_comm->community);
|
|
||||||
// enable header encryption
|
|
||||||
last_added_comm->header_encryption = HEADER_ENCRYPTION_ENABLED;
|
|
||||||
packet_header_setup_key(last_added_comm->community,
|
|
||||||
&(last_added_comm->header_encryption_ctx_static),
|
|
||||||
&(last_added_comm->header_encryption_ctx_dynamic),
|
|
||||||
&(last_added_comm->header_iv_ctx_static),
|
|
||||||
&(last_added_comm->header_iv_ctx_dynamic));
|
|
||||||
// dynamic key setup
|
|
||||||
last_added_comm->last_dynamic_key_time = time(NULL);
|
|
||||||
calculate_dynamic_key(last_added_comm->dynamic_key, /* destination */
|
|
||||||
last_added_comm->last_dynamic_key_time, /* time */
|
|
||||||
last_added_comm->community, /* community name */
|
|
||||||
sss->federation->community); /* federation name */
|
|
||||||
packet_header_change_dynamic_key(last_added_comm->dynamic_key,
|
|
||||||
&(last_added_comm->header_encryption_ctx_dynamic),
|
|
||||||
&(last_added_comm->header_iv_ctx_dynamic));
|
|
||||||
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- community name or regular expression
|
|
||||||
|
|
||||||
// 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(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(cmn_str);
|
|
||||||
HASH_ADD_PTR(sss->rules, rule, re);
|
|
||||||
num_regex++;
|
|
||||||
traceEvent(TRACE_INFO, "Added regular expression for allowed communities '%s'", cmn_str);
|
|
||||||
free(cmn_str);
|
|
||||||
last_added_comm = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
comm = (struct sn_community*)calloc(1,sizeof(struct sn_community));
|
|
||||||
|
|
||||||
if(comm != NULL) {
|
|
||||||
comm_init(comm, cmn_str);
|
|
||||||
/* loaded from file, this community is unpurgeable */
|
|
||||||
comm->purgeable = COMMUNITY_UNPURGEABLE;
|
|
||||||
/* we do not know if header encryption is used in this community,
|
|
||||||
* first packet will show. just in case, setup the key. */
|
|
||||||
comm->header_encryption = HEADER_ENCRYPTION_UNKNOWN;
|
|
||||||
packet_header_setup_key(comm->community,
|
|
||||||
&(comm->header_encryption_ctx_static),
|
|
||||||
&(comm->header_encryption_ctx_dynamic),
|
|
||||||
&(comm->header_iv_ctx_static),
|
|
||||||
&(comm->header_iv_ctx_dynamic));
|
|
||||||
HASH_ADD_STR(sss->communities, community, comm);
|
|
||||||
last_added_comm = comm;
|
|
||||||
|
|
||||||
num_communities++;
|
|
||||||
traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]",
|
|
||||||
(char*)comm->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) {
|
|
||||||
comm->auto_ip_net.net_addr = ntohl(net);
|
|
||||||
comm->auto_ip_net.net_bitlen = bitlen;
|
|
||||||
traceEvent(TRACE_INFO, "Assigned sub-network %s/%u to community '%s'.",
|
|
||||||
inet_ntoa(*(struct in_addr *) &net),
|
|
||||||
comm->auto_ip_net.net_bitlen,
|
|
||||||
comm->community);
|
|
||||||
} else {
|
|
||||||
assign_one_ip_subnet(sss, comm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(cmn_str);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fd);
|
|
||||||
|
|
||||||
if((num_regex + num_communities) == 0) {
|
|
||||||
traceEvent(TRACE_WARNING, "File %s does not contain any valid community names or regular expressions", sss->community_file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
traceEvent(TRACE_NORMAL, "Loaded %u fixed-name communities from %s",
|
|
||||||
num_communities, sss->community_file);
|
|
||||||
|
|
||||||
traceEvent(TRACE_NORMAL, "Loaded %u regular expressions for community name matching from %s",
|
|
||||||
num_regex, sss->community_file);
|
|
||||||
|
|
||||||
/* No new communities will be allowed */
|
|
||||||
sss->lock_communities = 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* *************************************************** */
|
|
||||||
|
|
||||||
/** Help message to print if the command line arguments are not valid. */
|
/** Help message to print if the command line arguments are not valid. */
|
||||||
static void help (int level) {
|
static void help (int level) {
|
||||||
|
@ -740,8 +525,6 @@ int main (int argc, char * const argv[]) {
|
||||||
struct passwd *pw = NULL;
|
struct passwd *pw = NULL;
|
||||||
#endif
|
#endif
|
||||||
struct peer_info *scan, *tmp;
|
struct peer_info *scan, *tmp;
|
||||||
struct sn_community *comm, *tmp_comm;
|
|
||||||
sn_user_t *user, *tmp_user;
|
|
||||||
|
|
||||||
|
|
||||||
sn_init(&sss_node);
|
sn_init(&sss_node);
|
||||||
|
@ -790,23 +573,7 @@ int main (int argc, char * const argv[]) {
|
||||||
traceEvent(TRACE_WARNING, "Disabled MAC and IP address spoofing protection. FOR TESTING ONLY, usage of user-password authentication (-I, -J, -P) recommended instead!");
|
traceEvent(TRACE_WARNING, "Disabled MAC and IP address spoofing protection. FOR TESTING ONLY, usage of user-password authentication (-I, -J, -P) recommended instead!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate shared secrets for user authentication; can be done only after
|
calculate_shared_secrets(&sss_node);
|
||||||
// federation name is known (-F) and community list completely read (-c)
|
|
||||||
traceEvent(TRACE_INFO, "started shared secrets calculation for edge authentication");
|
|
||||||
generate_private_key(sss_node.private_key, sss_node.federation->community + 1); /* skip '*' federation leading character */
|
|
||||||
HASH_ITER(hh, sss_node.communities, comm, tmp_comm) {
|
|
||||||
if(comm->is_federation) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
HASH_ITER(hh, comm->allowed_users, user, tmp_user) {
|
|
||||||
// calculate common shared secret (ECDH)
|
|
||||||
generate_shared_secret(user->shared_secret, sss_node.private_key, user->public_key);
|
|
||||||
// prepare for use as key
|
|
||||||
user->shared_secret_ctx = (he_context_t*)calloc(1, sizeof(speck_context_t));
|
|
||||||
speck_init((speck_context_t**)&user->shared_secret_ctx, user->shared_secret, 128);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
traceEvent(TRACE_NORMAL, "calculated shared secrets for edge authentication");
|
|
||||||
|
|
||||||
traceEvent(TRACE_DEBUG, "traceLevel is %d", getTraceLevel());
|
traceEvent(TRACE_DEBUG, "traceLevel is %d", getTraceLevel());
|
||||||
|
|
||||||
|
|
342
src/sn_utils.c
342
src/sn_utils.c
|
@ -23,6 +23,7 @@
|
||||||
int resolve_check (n2n_resolve_parameter_t *param, uint8_t resolution_request, time_t now);
|
int resolve_check (n2n_resolve_parameter_t *param, uint8_t resolution_request, time_t now);
|
||||||
int resolve_cancel_thread (n2n_resolve_parameter_t *param);
|
int resolve_cancel_thread (n2n_resolve_parameter_t *param);
|
||||||
|
|
||||||
|
|
||||||
static ssize_t sendto_peer (n2n_sn_t *sss,
|
static ssize_t sendto_peer (n2n_sn_t *sss,
|
||||||
const struct peer_info *peer,
|
const struct peer_info *peer,
|
||||||
const uint8_t *pktbuf,
|
const uint8_t *pktbuf,
|
||||||
|
@ -69,7 +70,7 @@ static int process_udp (n2n_sn_t *sss,
|
||||||
/* ************************************** */
|
/* ************************************** */
|
||||||
|
|
||||||
|
|
||||||
static void close_tcp_connection(n2n_sn_t *sss, n2n_tcp_connection_t *conn) {
|
void close_tcp_connection (n2n_sn_t *sss, n2n_tcp_connection_t *conn) {
|
||||||
|
|
||||||
struct sn_community *comm, *tmp_comm;
|
struct sn_community *comm, *tmp_comm;
|
||||||
struct peer_info *edge, *tmp_edge;
|
struct peer_info *edge, *tmp_edge;
|
||||||
|
@ -98,6 +99,308 @@ static void close_tcp_connection(n2n_sn_t *sss, n2n_tcp_connection_t *conn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* *************************************************** */
|
||||||
|
|
||||||
|
|
||||||
|
// generate shared secrets for user authentication; can be done only after
|
||||||
|
// federation name is known (-F) and community list completely read (-c)
|
||||||
|
void calculate_shared_secrets (n2n_sn_t *sss) {
|
||||||
|
|
||||||
|
struct sn_community *comm, *tmp_comm;
|
||||||
|
sn_user_t *user, *tmp_user;
|
||||||
|
|
||||||
|
traceEvent(TRACE_INFO, "started shared secrets calculation for edge authentication");
|
||||||
|
|
||||||
|
generate_private_key(sss->private_key, sss->federation->community + 1); /* skip '*' federation leading character */
|
||||||
|
HASH_ITER(hh, sss->communities, comm, tmp_comm) {
|
||||||
|
if(comm->is_federation) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
HASH_ITER(hh, comm->allowed_users, user, tmp_user) {
|
||||||
|
// calculate common shared secret (ECDH)
|
||||||
|
generate_shared_secret(user->shared_secret, sss->private_key, user->public_key);
|
||||||
|
// prepare for use as key
|
||||||
|
user->shared_secret_ctx = (he_context_t*)calloc(1, sizeof(speck_context_t));
|
||||||
|
speck_init((speck_context_t**)&user->shared_secret_ctx, user->shared_secret, 128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
traceEvent(TRACE_NORMAL, "calculated shared secrets for edge authentication");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Load the list of allowed communities. Existing/previous ones will be removed,
|
||||||
|
* return 0 on success, -1 if file not found, -2 if no valid entries found
|
||||||
|
*/
|
||||||
|
int load_allowed_sn_community (n2n_sn_t *sss) {
|
||||||
|
|
||||||
|
char buffer[4096], *line, *cmn_str, net_str[20], format[20];
|
||||||
|
|
||||||
|
sn_user_t *user, *tmp_user;
|
||||||
|
n2n_desc_t username;
|
||||||
|
n2n_private_public_key_t public_key;
|
||||||
|
uint8_t ascii_public_key[(N2N_PRIVATE_PUBLIC_KEY_SIZE * 8 + 5) / 6 + 1];
|
||||||
|
|
||||||
|
dec_ip_str_t ip_str = {'\0'};
|
||||||
|
uint8_t bitlen;
|
||||||
|
in_addr_t net;
|
||||||
|
uint32_t mask;
|
||||||
|
FILE *fd = fopen(sss->community_file, "r");
|
||||||
|
|
||||||
|
struct sn_community *comm, *tmp_comm, *last_added_comm = NULL;
|
||||||
|
struct peer_info *edge, *tmp_edge;
|
||||||
|
node_supernode_association_t *assoc, *tmp_assoc;
|
||||||
|
n2n_tcp_connection_t *conn;
|
||||||
|
|
||||||
|
n2n_common_t cmn;
|
||||||
|
uint8_t rereg_buf[N2N_SN_PKTBUF_SIZE];
|
||||||
|
size_t encx = 0;
|
||||||
|
n2n_sock_str_t sockbuf;
|
||||||
|
|
||||||
|
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", sss->community_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove communities (not: federation)
|
||||||
|
HASH_ITER(hh, sss->communities, comm, tmp_comm) {
|
||||||
|
if(comm->is_federation) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send RE_REGISTER_SUPER to edges if this is a user/pw auth community
|
||||||
|
if(comm->allowed_users) {
|
||||||
|
// prepare
|
||||||
|
cmn.ttl = N2N_DEFAULT_TTL;
|
||||||
|
cmn.pc = n2n_re_register_super;
|
||||||
|
cmn.flags = N2N_FLAGS_FROM_SUPERNODE;
|
||||||
|
memcpy(cmn.community, comm->community, N2N_COMMUNITY_SIZE);
|
||||||
|
encode_common(rereg_buf, &encx, &cmn);
|
||||||
|
|
||||||
|
HASH_ITER(hh, comm->edges, edge, tmp_edge) {
|
||||||
|
// send
|
||||||
|
traceEvent(TRACE_DEBUG, "send RE_REGISTER_SUPER to %s",
|
||||||
|
sock_to_cstr(sockbuf, &(edge->sock)));
|
||||||
|
|
||||||
|
packet_header_encrypt(rereg_buf, encx, encx,
|
||||||
|
comm->header_encryption_ctx_dynamic, comm->header_iv_ctx_dynamic,
|
||||||
|
time_stamp());
|
||||||
|
|
||||||
|
/* sent = */ sendto_peer(sss, edge, rereg_buf, encx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all edges from community
|
||||||
|
HASH_ITER(hh, comm->edges, edge, tmp_edge) {
|
||||||
|
// remove all edge associations (with other supernodes)
|
||||||
|
HASH_ITER(hh, comm->assoc, assoc, tmp_assoc) {
|
||||||
|
HASH_DEL(comm->assoc, assoc);
|
||||||
|
free(assoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// close TCP connections, if any (also causes reconnect)
|
||||||
|
// and delete edge from list
|
||||||
|
if((edge->socket_fd != sss->sock) && (edge->socket_fd >= 0)) {
|
||||||
|
HASH_FIND_INT(sss->tcp_connections, &(edge->socket_fd), conn);
|
||||||
|
close_tcp_connection(sss, conn); /* also deletes the edge */
|
||||||
|
} else {
|
||||||
|
HASH_DEL(comm->edges, edge);
|
||||||
|
free(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove allowed users from community
|
||||||
|
HASH_ITER(hh, comm->allowed_users, user, tmp_user) {
|
||||||
|
free(user->shared_secret_ctx);
|
||||||
|
HASH_DEL(comm->allowed_users, user);
|
||||||
|
free(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove community
|
||||||
|
HASH_DEL(sss->communities, comm);
|
||||||
|
if(NULL != comm->header_encryption_ctx_static) {
|
||||||
|
// remove header encryption keys
|
||||||
|
free(comm->header_encryption_ctx_static);
|
||||||
|
free(comm->header_iv_ctx_static);
|
||||||
|
free(comm->header_encryption_ctx_dynamic);
|
||||||
|
free(comm->header_iv_ctx_dynamic);
|
||||||
|
}
|
||||||
|
free(comm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all regular expressions for allowed communities
|
||||||
|
HASH_ITER(hh, sss->rules, re, tmp_re) {
|
||||||
|
HASH_DEL(sss->rules, re);
|
||||||
|
free(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
// format definition for possible user-key entries
|
||||||
|
sprintf(format, "%c %%%ds %%%ds", N2N_USER_KEY_LINE_STARTER, N2N_DESC_SIZE - 1, sizeof(ascii_public_key)-1);
|
||||||
|
|
||||||
|
while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) {
|
||||||
|
int len = strlen(line);
|
||||||
|
|
||||||
|
if((len < 2) || line[0] == '#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
len--;
|
||||||
|
while(len > 0) {
|
||||||
|
if((line[len] == '\n') || (line[len] == '\r')) {
|
||||||
|
line[len] = '\0';
|
||||||
|
len--;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the loop above does not always determine correct 'len'
|
||||||
|
len = strlen(line);
|
||||||
|
|
||||||
|
// user-key line for edge authentication?
|
||||||
|
if(line[0] == N2N_USER_KEY_LINE_STARTER) { /* special first character */
|
||||||
|
if(sscanf(line, format, username, ascii_public_key) == 2) { /* correct format */
|
||||||
|
if(last_added_comm) { /* is there a valid community to add users to */
|
||||||
|
user = (sn_user_t*)calloc(1, sizeof(sn_user_t));
|
||||||
|
if(user) {
|
||||||
|
// username
|
||||||
|
memcpy(user->name, username, sizeof(username));
|
||||||
|
// public key
|
||||||
|
ascii_to_bin(public_key, ascii_public_key);
|
||||||
|
memcpy(user->public_key, public_key, sizeof(public_key));
|
||||||
|
// common shared secret will be calculated later
|
||||||
|
// add to list
|
||||||
|
HASH_ADD(hh, last_added_comm->allowed_users, public_key, sizeof(n2n_private_public_key_t), user);
|
||||||
|
traceEvent(TRACE_INFO, "Added user '%s' with public key '%s' to community '%s'",
|
||||||
|
user->name, ascii_public_key, last_added_comm->community);
|
||||||
|
// enable header encryption
|
||||||
|
last_added_comm->header_encryption = HEADER_ENCRYPTION_ENABLED;
|
||||||
|
packet_header_setup_key(last_added_comm->community,
|
||||||
|
&(last_added_comm->header_encryption_ctx_static),
|
||||||
|
&(last_added_comm->header_encryption_ctx_dynamic),
|
||||||
|
&(last_added_comm->header_iv_ctx_static),
|
||||||
|
&(last_added_comm->header_iv_ctx_dynamic));
|
||||||
|
// dynamic key setup
|
||||||
|
last_added_comm->last_dynamic_key_time = time(NULL);
|
||||||
|
calculate_dynamic_key(last_added_comm->dynamic_key, /* destination */
|
||||||
|
last_added_comm->last_dynamic_key_time, /* time */
|
||||||
|
last_added_comm->community, /* community name */
|
||||||
|
sss->federation->community); /* federation name */
|
||||||
|
packet_header_change_dynamic_key(last_added_comm->dynamic_key,
|
||||||
|
&(last_added_comm->header_encryption_ctx_dynamic),
|
||||||
|
&(last_added_comm->header_iv_ctx_dynamic));
|
||||||
|
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- community name or regular expression
|
||||||
|
|
||||||
|
// 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(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(cmn_str);
|
||||||
|
HASH_ADD_PTR(sss->rules, rule, re);
|
||||||
|
num_regex++;
|
||||||
|
traceEvent(TRACE_INFO, "Added regular expression for allowed communities '%s'", cmn_str);
|
||||||
|
free(cmn_str);
|
||||||
|
last_added_comm = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comm = (struct sn_community*)calloc(1,sizeof(struct sn_community));
|
||||||
|
|
||||||
|
if(comm != NULL) {
|
||||||
|
comm_init(comm, cmn_str);
|
||||||
|
/* loaded from file, this community is unpurgeable */
|
||||||
|
comm->purgeable = COMMUNITY_UNPURGEABLE;
|
||||||
|
/* we do not know if header encryption is used in this community,
|
||||||
|
* first packet will show. just in case, setup the key. */
|
||||||
|
comm->header_encryption = HEADER_ENCRYPTION_UNKNOWN;
|
||||||
|
packet_header_setup_key(comm->community,
|
||||||
|
&(comm->header_encryption_ctx_static),
|
||||||
|
&(comm->header_encryption_ctx_dynamic),
|
||||||
|
&(comm->header_iv_ctx_static),
|
||||||
|
&(comm->header_iv_ctx_dynamic));
|
||||||
|
HASH_ADD_STR(sss->communities, community, comm);
|
||||||
|
last_added_comm = comm;
|
||||||
|
|
||||||
|
num_communities++;
|
||||||
|
traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]",
|
||||||
|
(char*)comm->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) {
|
||||||
|
comm->auto_ip_net.net_addr = ntohl(net);
|
||||||
|
comm->auto_ip_net.net_bitlen = bitlen;
|
||||||
|
traceEvent(TRACE_INFO, "Assigned sub-network %s/%u to community '%s'.",
|
||||||
|
inet_ntoa(*(struct in_addr *) &net),
|
||||||
|
comm->auto_ip_net.net_bitlen,
|
||||||
|
comm->community);
|
||||||
|
} else {
|
||||||
|
assign_one_ip_subnet(sss, comm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(cmn_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
if((num_regex + num_communities) == 0) {
|
||||||
|
traceEvent(TRACE_WARNING, "File %s does not contain any valid community names or regular expressions", sss->community_file);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
traceEvent(TRACE_NORMAL, "Loaded %u fixed-name communities from %s",
|
||||||
|
num_communities, sss->community_file);
|
||||||
|
|
||||||
|
traceEvent(TRACE_NORMAL, "Loaded %u regular expressions for community name matching from %s",
|
||||||
|
num_regex, sss->community_file);
|
||||||
|
|
||||||
|
/* No new communities will be allowed */
|
||||||
|
sss->lock_communities = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* *************************************************** */
|
||||||
|
|
||||||
|
|
||||||
/** Send a datagram to a file descriptor socket.
|
/** Send a datagram to a file descriptor socket.
|
||||||
*
|
*
|
||||||
* @return -1 on error otherwise number of bytes sent
|
* @return -1 on error otherwise number of bytes sent
|
||||||
|
@ -452,7 +755,6 @@ void sn_term (n2n_sn_t *sss) {
|
||||||
}
|
}
|
||||||
sss->tcp_sock = -1;
|
sss->tcp_sock = -1;
|
||||||
|
|
||||||
|
|
||||||
if(sss->mgmt_sock >= 0) {
|
if(sss->mgmt_sock >= 0) {
|
||||||
closesocket(sss->mgmt_sock);
|
closesocket(sss->mgmt_sock);
|
||||||
}
|
}
|
||||||
|
@ -1044,7 +1346,9 @@ static int purge_expired_communities (n2n_sn_t *sss,
|
||||||
if(NULL != comm->header_encryption_ctx_static) {
|
if(NULL != comm->header_encryption_ctx_static) {
|
||||||
/* this should not happen as 'purgeable' and thus only communities w/o encrypted header here */
|
/* this should not happen as 'purgeable' and thus only communities w/o encrypted header here */
|
||||||
free(comm->header_encryption_ctx_static);
|
free(comm->header_encryption_ctx_static);
|
||||||
|
free(comm->header_iv_ctx_static);
|
||||||
free(comm->header_encryption_ctx_dynamic);
|
free(comm->header_encryption_ctx_dynamic);
|
||||||
|
free(comm->header_iv_ctx_dynamic);
|
||||||
}
|
}
|
||||||
// remove all associations
|
// remove all associations
|
||||||
HASH_ITER(hh, comm->assoc, assoc, tmp_assoc) {
|
HASH_ITER(hh, comm->assoc, assoc, tmp_assoc) {
|
||||||
|
@ -1118,6 +1422,40 @@ static int process_mgmt (n2n_sn_t *sss,
|
||||||
|
|
||||||
traceEvent(TRACE_DEBUG, "process_mgmt");
|
traceEvent(TRACE_DEBUG, "process_mgmt");
|
||||||
|
|
||||||
|
// process input, if any
|
||||||
|
if((0 == memcmp(mgmt_buf, "help", 4)) || (0 == memcmp(mgmt_buf, "?", 1))) {
|
||||||
|
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||||
|
"Help for supernode management console:\n"
|
||||||
|
"\thelp | This help message\n"
|
||||||
|
"\treload_communities | Reloads communities and user's public keys\n");
|
||||||
|
sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize);
|
||||||
|
return 0; /* no status output afterwards */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(0 == memcmp(mgmt_buf, "reload_communities", 18)) {
|
||||||
|
if(!sss->community_file) {
|
||||||
|
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||||
|
"No community file provided (-c command line option)\n");
|
||||||
|
sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize);
|
||||||
|
return 0; /* no status output afterwards */
|
||||||
|
}
|
||||||
|
traceEvent(TRACE_NORMAL, "process_mgmt sees 'reload_communities' command.");
|
||||||
|
|
||||||
|
if(load_allowed_sn_community(sss)) {
|
||||||
|
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||||
|
"Error while re-loading community file (not found or no valid content)\n");
|
||||||
|
sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize);
|
||||||
|
return 0; /* no status output afterwards */
|
||||||
|
}
|
||||||
|
calculate_shared_secrets(sss);
|
||||||
|
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||||
|
"OK.\n");
|
||||||
|
sendto_mgmt(sss, sender_sock, (const uint8_t *) resbuf, ressize);
|
||||||
|
return 0; /* no status output afterwards */
|
||||||
|
}
|
||||||
|
|
||||||
|
// output current status
|
||||||
|
|
||||||
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||||
" ### | TAP | MAC | EDGE | HINT | LAST SEEN\n");
|
" ### | TAP | MAC | EDGE | HINT | LAST SEEN\n");
|
||||||
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
ressize += snprintf(resbuf + ressize, N2N_SN_PKTBUF_SIZE - ressize,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user