|
|
@ -29,7 +29,7 @@ |
|
|
|
|
|
|
|
#define N2N_SN_MGMT_PORT 5645 |
|
|
|
|
|
|
|
struct sn_stats { |
|
|
|
typedef struct sn_stats { |
|
|
|
size_t errors; /* Number of errors encountered. */ |
|
|
|
size_t reg_super; /* Number of REGISTER_SUPER requests received. */ |
|
|
|
size_t reg_super_nak; /* Number of REGISTER_SUPER requests declined. */ |
|
|
@ -37,28 +37,27 @@ struct sn_stats { |
|
|
|
size_t broadcast; /* Number of messages broadcast to a community. */ |
|
|
|
time_t last_fwd; /* Time when last message was forwarded. */ |
|
|
|
time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */ |
|
|
|
}; |
|
|
|
} sn_stats_t; |
|
|
|
|
|
|
|
typedef struct sn_stats sn_stats_t; |
|
|
|
struct sn_community { |
|
|
|
char community[N2N_COMMUNITY_SIZE]; |
|
|
|
struct peer_info *edges; /* Link list of registered edges. */ |
|
|
|
|
|
|
|
struct n2n_sn { |
|
|
|
UT_hash_handle hh; /* makes this structure hashable */ |
|
|
|
}; |
|
|
|
|
|
|
|
typedef struct n2n_sn { |
|
|
|
time_t start_time; /* Used to measure uptime. */ |
|
|
|
sn_stats_t stats; |
|
|
|
int daemon; /* If non-zero then daemonise. */ |
|
|
|
uint16_t lport; /* Local UDP port to bind to. */ |
|
|
|
int sock; /* Main socket for UDP traffic with edges. */ |
|
|
|
int mgmt_sock; /* management socket. */ |
|
|
|
struct peer_info * edges; /* Link list of registered edges. */ |
|
|
|
}; |
|
|
|
int lock_communities; /* If true, only loaded communities can be used. */ |
|
|
|
struct sn_community *communities; |
|
|
|
} n2n_sn_t; |
|
|
|
|
|
|
|
typedef struct n2n_sn n2n_sn_t; |
|
|
|
|
|
|
|
struct n2n_allowed_communities { |
|
|
|
char community[N2N_COMMUNITY_SIZE]; |
|
|
|
UT_hash_handle hh; /* makes this structure hashable */ |
|
|
|
}; |
|
|
|
|
|
|
|
static struct n2n_allowed_communities *allowed_communities = NULL; |
|
|
|
#define HASH_FIND_COMMUNITY(head,name,out) HASH_FIND_STR(head,name,out) |
|
|
|
|
|
|
|
static int try_forward(n2n_sn_t * sss, |
|
|
|
const n2n_common_t * cmn, |
|
|
@ -85,7 +84,6 @@ static int init_sn(n2n_sn_t * sss) { |
|
|
|
sss->lport = N2N_SN_LPORT_DEFAULT; |
|
|
|
sss->sock = -1; |
|
|
|
sss->mgmt_sock = -1; |
|
|
|
sss->edges = NULL; |
|
|
|
|
|
|
|
return 0; /* OK */ |
|
|
|
} |
|
|
@ -94,6 +92,8 @@ static int init_sn(n2n_sn_t * sss) { |
|
|
|
* it. */ |
|
|
|
static void deinit_sn(n2n_sn_t * sss) |
|
|
|
{ |
|
|
|
struct sn_community *community, *tmp; |
|
|
|
|
|
|
|
if(sss->sock >= 0) |
|
|
|
{ |
|
|
|
closesocket(sss->sock); |
|
|
@ -106,7 +106,11 @@ static void deinit_sn(n2n_sn_t * sss) |
|
|
|
} |
|
|
|
sss->mgmt_sock=-1; |
|
|
|
|
|
|
|
clear_peer_list(&sss->edges); |
|
|
|
HASH_ITER(hh, sss->communities, community, tmp) { |
|
|
|
clear_peer_list(&community->edges); |
|
|
|
HASH_DEL(sss->communities, community); |
|
|
|
free(community); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -125,7 +129,7 @@ static uint16_t reg_lifetime(n2n_sn_t * sss) { |
|
|
|
* supernode. */ |
|
|
|
static int update_edge(n2n_sn_t * sss, |
|
|
|
const n2n_mac_t edgeMac, |
|
|
|
const n2n_community_t community, |
|
|
|
struct sn_community *community, |
|
|
|
const n2n_sock_t * sender_sock, |
|
|
|
time_t now) { |
|
|
|
macstr_t mac_buf; |
|
|
@ -136,18 +140,18 @@ static int update_edge(n2n_sn_t * sss, |
|
|
|
macaddr_str(mac_buf, edgeMac), |
|
|
|
sock_to_cstr(sockbuf, sender_sock)); |
|
|
|
|
|
|
|
HASH_FIND_PEER(sss->edges, edgeMac, scan); |
|
|
|
HASH_FIND_PEER(community->edges, edgeMac, scan); |
|
|
|
|
|
|
|
if(NULL == scan) { |
|
|
|
/* Not known */ |
|
|
|
|
|
|
|
scan = (struct peer_info*)calloc(1, sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */ |
|
|
|
|
|
|
|
memcpy(scan->community_name, community, sizeof(n2n_community_t)); |
|
|
|
memcpy(scan->community_name, community->community, sizeof(n2n_community_t)); |
|
|
|
memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t)); |
|
|
|
memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); |
|
|
|
|
|
|
|
HASH_ADD_PEER(sss->edges, scan); |
|
|
|
HASH_ADD_PEER(community->edges, scan); |
|
|
|
|
|
|
|
traceEvent(TRACE_INFO, "update_edge created %s ==> %s", |
|
|
|
macaddr_str(mac_buf, edgeMac), |
|
|
@ -212,11 +216,6 @@ static ssize_t sendto_sock(n2n_sn_t * sss, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Try to forward a message to a unicast MAC. If the MAC is unknown then
|
|
|
|
* broadcast to all edges in the destination community. |
|
|
|
*/ |
|
|
|
static int try_forward(n2n_sn_t * sss, |
|
|
|
const n2n_common_t * cmn, |
|
|
|
const n2n_mac_t dstMac, |
|
|
@ -224,10 +223,18 @@ static int try_forward(n2n_sn_t * sss, |
|
|
|
size_t pktsize) |
|
|
|
{ |
|
|
|
struct peer_info * scan; |
|
|
|
struct sn_community *community; |
|
|
|
macstr_t mac_buf; |
|
|
|
n2n_sock_str_t sockbuf; |
|
|
|
|
|
|
|
HASH_FIND_PEER(sss->edges, dstMac, scan); |
|
|
|
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn->community, community); |
|
|
|
|
|
|
|
if(!community) { |
|
|
|
traceEvent(TRACE_DEBUG, "try_forward unknown community %s", cmn->community); |
|
|
|
return(-1); |
|
|
|
} |
|
|
|
|
|
|
|
HASH_FIND_PEER(community->edges, dstMac, scan); |
|
|
|
|
|
|
|
if(NULL != scan) |
|
|
|
{ |
|
|
@ -257,9 +264,10 @@ static int try_forward(n2n_sn_t * sss, |
|
|
|
traceEvent(TRACE_DEBUG, "try_forward unknown MAC"); |
|
|
|
|
|
|
|
/* Not a known MAC so drop. */ |
|
|
|
return(-2); |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
return(0); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -275,16 +283,18 @@ static int try_broadcast(n2n_sn_t * sss, |
|
|
|
size_t pktsize) |
|
|
|
{ |
|
|
|
struct peer_info *scan, *tmp; |
|
|
|
struct sn_community *community; |
|
|
|
macstr_t mac_buf; |
|
|
|
n2n_sock_str_t sockbuf; |
|
|
|
|
|
|
|
traceEvent(TRACE_DEBUG, "try_broadcast"); |
|
|
|
|
|
|
|
HASH_ITER(hh, sss->edges, scan, tmp) { |
|
|
|
if(0 == (memcmp(scan->community_name, cmn->community, sizeof(n2n_community_t))) |
|
|
|
&& (0 != memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)))) |
|
|
|
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn->community, community); |
|
|
|
|
|
|
|
if(community) { |
|
|
|
HASH_ITER(hh, community->edges, scan, tmp) { |
|
|
|
if(memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0) { |
|
|
|
/* REVISIT: exclude if the destination socket is where the packet came from. */ |
|
|
|
{ |
|
|
|
int data_sent_len; |
|
|
|
|
|
|
|
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize); |
|
|
@ -308,6 +318,9 @@ static int try_broadcast(n2n_sn_t * sss, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else |
|
|
|
traceEvent(TRACE_WARNING, "ignoring broadcast on unknown community %s\n", |
|
|
|
cmn->community); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
@ -321,7 +334,9 @@ static int process_mgmt(n2n_sn_t * sss, |
|
|
|
{ |
|
|
|
char resbuf[N2N_SN_PKTBUF_SIZE]; |
|
|
|
size_t ressize=0; |
|
|
|
uint num_edges=0; |
|
|
|
ssize_t r; |
|
|
|
struct sn_community *community, *tmp; |
|
|
|
|
|
|
|
traceEvent(TRACE_DEBUG, "process_mgmt"); |
|
|
|
|
|
|
@ -331,9 +346,13 @@ static int process_mgmt(n2n_sn_t * sss, |
|
|
|
ressize += snprintf(resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, |
|
|
|
"uptime %lu\n", (now - sss->start_time)); |
|
|
|
|
|
|
|
HASH_ITER(hh, sss->communities, community, tmp) { |
|
|
|
num_edges += HASH_COUNT(community->edges); |
|
|
|
} |
|
|
|
|
|
|
|
ressize += snprintf(resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, |
|
|
|
"edges %u\n", |
|
|
|
HASH_COUNT(sss->edges)); |
|
|
|
num_edges); |
|
|
|
|
|
|
|
ressize += snprintf(resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize, |
|
|
|
"errors %u\n", |
|
|
@ -376,31 +395,13 @@ static int process_mgmt(n2n_sn_t * sss, |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/** Check if the specified community is allowed by the
|
|
|
|
* supernode configuration |
|
|
|
* @return 0 = community not allowed, 1 = community allowed |
|
|
|
* |
|
|
|
*/ |
|
|
|
static int allowed_n2n_community(n2n_common_t *cmn) { |
|
|
|
if(allowed_communities != NULL) { |
|
|
|
struct n2n_allowed_communities *c; |
|
|
|
|
|
|
|
HASH_FIND_STR(allowed_communities, (const char*)cmn->community, c); |
|
|
|
return((c == NULL) ? 0 : 1); |
|
|
|
} else { |
|
|
|
/* If no allowed community is defined, all communities are allowed */ |
|
|
|
} |
|
|
|
|
|
|
|
return(1); |
|
|
|
} |
|
|
|
|
|
|
|
/** Load the list of allowed communities. Existing/previous ones will be removed
|
|
|
|
* |
|
|
|
*/ |
|
|
|
static int load_allowed_n2n_communities(char *path) { |
|
|
|
static int load_allowed_sn_community(n2n_sn_t *sss, char *path) { |
|
|
|
char buffer[4096], *line; |
|
|
|
FILE *fd = fopen(path, "r"); |
|
|
|
struct n2n_allowed_communities *s, *tmp; |
|
|
|
struct sn_community *s, *tmp; |
|
|
|
uint32_t num_communities = 0; |
|
|
|
|
|
|
|
if(fd == NULL) { |
|
|
@ -408,8 +409,10 @@ static int load_allowed_n2n_communities(char *path) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
HASH_ITER(hh, allowed_communities, s, tmp) |
|
|
|
HASH_ITER(hh, sss->communities, s, tmp) { |
|
|
|
HASH_DEL(sss->communities, s); |
|
|
|
free(s); |
|
|
|
} |
|
|
|
|
|
|
|
while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { |
|
|
|
int len = strlen(line); |
|
|
@ -426,12 +429,12 @@ static int load_allowed_n2n_communities(char *path) { |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
s = (struct n2n_allowed_communities*)malloc(sizeof(struct n2n_allowed_communities)); |
|
|
|
s = (struct sn_community*)calloc(1,sizeof(struct sn_community)); |
|
|
|
|
|
|
|
if(s != NULL) { |
|
|
|
strncpy((char*)s->community, line, N2N_COMMUNITY_SIZE-1); |
|
|
|
s->community[N2N_COMMUNITY_SIZE-1] = '\0'; |
|
|
|
HASH_ADD_STR(allowed_communities, community, s); |
|
|
|
HASH_ADD_STR(sss->communities, community, s); |
|
|
|
num_communities++; |
|
|
|
traceEvent(TRACE_INFO, "Added allowed community '%s' [total: %u]", |
|
|
|
(char*)s->community, num_communities); |
|
|
@ -443,6 +446,9 @@ static int load_allowed_n2n_communities(char *path) { |
|
|
|
traceEvent(TRACE_NORMAL, "Loaded %u communities from %s", |
|
|
|
num_communities, path); |
|
|
|
|
|
|
|
/* No new communities will be allowed */ |
|
|
|
sss->lock_communities = 1; |
|
|
|
|
|
|
|
return(0); |
|
|
|
} |
|
|
|
|
|
|
@ -617,19 +623,34 @@ static int process_udp(n2n_sn_t * sss, |
|
|
|
n2n_common_t cmn2; |
|
|
|
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; |
|
|
|
size_t encx=0; |
|
|
|
struct sn_community *community; |
|
|
|
|
|
|
|
/* Edge requesting registration with us. */ |
|
|
|
sss->stats.last_reg_super=now; |
|
|
|
++(sss->stats.reg_super); |
|
|
|
decode_REGISTER_SUPER(®, &cmn, udp_buf, &rem, &idx); |
|
|
|
|
|
|
|
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn.community, community); |
|
|
|
|
|
|
|
/*
|
|
|
|
Before we move any further, we need to check if the requested |
|
|
|
community is allowed by the supernode. In case it is not we do |
|
|
|
not report any message back to the edge to hide the supernode |
|
|
|
existance (better from the security standpoint) |
|
|
|
*/ |
|
|
|
if(allowed_n2n_community(&cmn)) { |
|
|
|
if(!community && !sss->lock_communities) { |
|
|
|
community = calloc(1, sizeof(struct sn_community)); |
|
|
|
|
|
|
|
if(community) { |
|
|
|
strncpy(community->community, (char*)cmn.community, N2N_COMMUNITY_SIZE-1); |
|
|
|
community->community[N2N_COMMUNITY_SIZE-1] = '\0'; |
|
|
|
HASH_ADD_STR(sss->communities, community, community); |
|
|
|
|
|
|
|
traceEvent(TRACE_INFO, "New community: %s", community->community); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if(community) { |
|
|
|
cmn2.ttl = N2N_DEFAULT_TTL; |
|
|
|
cmn2.pc = n2n_register_super_ack; |
|
|
|
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; |
|
|
@ -650,7 +671,7 @@ static int process_udp(n2n_sn_t * sss, |
|
|
|
macaddr_str(mac_buf, reg.edgeMac), |
|
|
|
sock_to_cstr(sockbuf, &(ack.sock))); |
|
|
|
|
|
|
|
update_edge(sss, reg.edgeMac, cmn.community, &(ack.sock), now); |
|
|
|
update_edge(sss, reg.edgeMac, community, &(ack.sock), now); |
|
|
|
|
|
|
|
encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack); |
|
|
|
|
|
|
@ -670,7 +691,7 @@ static int process_udp(n2n_sn_t * sss, |
|
|
|
size_t encx=0; |
|
|
|
n2n_common_t cmn2; |
|
|
|
n2n_PEER_INFO_t pi; |
|
|
|
struct peer_info *scan; |
|
|
|
struct sn_community *community; |
|
|
|
|
|
|
|
decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx ); |
|
|
|
|
|
|
@ -678,7 +699,12 @@ static int process_udp(n2n_sn_t * sss, |
|
|
|
macaddr_str( mac_buf, query.srcMac ), |
|
|
|
macaddr_str( mac_buf2, query.targetMac ) ); |
|
|
|
|
|
|
|
HASH_FIND_PEER(sss->edges, query.targetMac, scan); |
|
|
|
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn.community, community); |
|
|
|
|
|
|
|
if(community) { |
|
|
|
struct peer_info *scan; |
|
|
|
HASH_FIND_PEER(community->edges, query.targetMac, scan); |
|
|
|
|
|
|
|
if (scan) { |
|
|
|
cmn2.ttl = N2N_DEFAULT_TTL; |
|
|
|
cmn2.pc = n2n_peer_info; |
|
|
@ -700,6 +726,7 @@ static int process_udp(n2n_sn_t * sss, |
|
|
|
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s", |
|
|
|
macaddr_str( mac_buf, query.targetMac ) ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
@ -754,7 +781,7 @@ static int setOption(int optkey, char *_optarg, n2n_sn_t *sss) { |
|
|
|
break; |
|
|
|
|
|
|
|
case 'c': /* community file */ |
|
|
|
load_allowed_n2n_communities(optarg); |
|
|
|
load_allowed_sn_community(sss, optarg); |
|
|
|
break; |
|
|
|
|
|
|
|
case 'f': /* foreground */ |
|
|
@ -889,6 +916,7 @@ static int loadFromFile(const char *path, n2n_sn_t *sss) { |
|
|
|
/* *************************************************** */ |
|
|
|
|
|
|
|
static void dump_registrations(int signo) { |
|
|
|
struct sn_community *comm, *ctmp; |
|
|
|
struct peer_info *list, *tmp; |
|
|
|
char buf[32]; |
|
|
|
time_t now = time(NULL); |
|
|
@ -896,7 +924,8 @@ static void dump_registrations(int signo) { |
|
|
|
|
|
|
|
traceEvent(TRACE_NORMAL, "===================================="); |
|
|
|
|
|
|
|
HASH_ITER(hh, sss_node.edges, list, tmp) { |
|
|
|
HASH_ITER(hh, sss_node.communities, comm, ctmp) { |
|
|
|
HASH_ITER(hh, comm->edges, list, tmp) { |
|
|
|
if(list->sock.family == AF_INET) |
|
|
|
traceEvent(TRACE_NORMAL, "[id: %u][MAC: %s][edge: %u.%u.%u.%u:%u][community: %s][last seen: %u sec ago]", |
|
|
|
++num, macaddr_str(buf, list->mac_addr), |
|
|
@ -910,6 +939,7 @@ static void dump_registrations(int signo) { |
|
|
|
(char*)list->community_name, |
|
|
|
now-list->last_seen); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
traceEvent(TRACE_NORMAL, "===================================="); |
|
|
|
} |
|
|
@ -981,6 +1011,7 @@ static int run_loop(n2n_sn_t * sss) { |
|
|
|
uint8_t pktbuf[N2N_SN_PKTBUF_SIZE]; |
|
|
|
int keep_running=1; |
|
|
|
time_t last_purge_edges = 0; |
|
|
|
struct sn_community *comm, *tmp; |
|
|
|
|
|
|
|
sss->start_time = time(NULL); |
|
|
|
|
|
|
@ -1055,7 +1086,9 @@ static int run_loop(n2n_sn_t * sss) { |
|
|
|
traceEvent(TRACE_DEBUG, "timeout"); |
|
|
|
} |
|
|
|
|
|
|
|
purge_expired_registrations( &sss->edges, &last_purge_edges ); |
|
|
|
HASH_ITER(hh, sss->communities, comm, tmp) { |
|
|
|
purge_expired_registrations( &comm->edges, &last_purge_edges ); |
|
|
|
} |
|
|
|
|
|
|
|
} /* while */ |
|
|
|
|
|
|
|