mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
Header Encryption
This commit is contained in:
parent
159a088696
commit
789dd90272
|
@ -17,19 +17,11 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
/* Header encryption indicators */
|
||||
#define HEADER_ENCRYPTION_UNKNOWN 0
|
||||
#define HEADER_ENCRYPTION_NONE 1
|
||||
#define HEADER_ENCRYPTION_ENABLED 2
|
||||
|
||||
uint32_t packet_header_decrypt (uint8_t packet[], uint8_t packet_len,
|
||||
uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
|
||||
char * community_name, he_context_t * ctx);
|
||||
|
||||
int8_t packet_header_decrypt_if_required (uint8_t packet[], uint16_t packet_len,
|
||||
struct sn_community * communities);
|
||||
|
||||
int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx);
|
||||
|
||||
|
||||
void packet_header_setup_key (char * community_name, he_context_t * ctx);
|
||||
void packet_header_setup_key (const char * community_name, he_context_t ** ctx);
|
||||
|
|
|
@ -60,6 +60,11 @@
|
|||
bits of transform_id; will be obsolete as soon as compression gets
|
||||
its own field in the packet. REVISIT then. */
|
||||
|
||||
/* Header encryption indicators */
|
||||
#define HEADER_ENCRYPTION_UNKNOWN 0
|
||||
#define HEADER_ENCRYPTION_NONE 1
|
||||
#define HEADER_ENCRYPTION_ENABLED 2
|
||||
|
||||
#define DEFAULT_MTU 1290
|
||||
|
||||
#define HASH_ADD_PEER(head,add) \
|
||||
|
|
13
src/edge.c
13
src/edge.c
|
@ -154,7 +154,7 @@ static void help() {
|
|||
#ifndef __APPLE__
|
||||
"[-D] "
|
||||
#endif
|
||||
"[-r] [-E] [-v] [-i <reg_interval>] [-L <reg_ttl>] [-t <mgmt port>] [-A[<cipher>]] [-z[<compression algo>]] [-h]\n\n");
|
||||
"[-r] [-E] [-v] [-i <reg_interval>] [-L <reg_ttl>] [-t <mgmt port>] [-A[<cipher>]] [-H] [-z[<compression algo>]] [-h]\n\n");
|
||||
|
||||
#if defined(N2N_CAN_NAME_IFACE)
|
||||
printf("-d <tun device> | tun device name\n");
|
||||
|
@ -192,6 +192,7 @@ static void help() {
|
|||
printf("-A4 | Use ChaCha20 for payload encryption. Requires a key.\n");
|
||||
#endif
|
||||
printf("-A5 | Use Speck for payload encryption. Requires a key.\n");
|
||||
printf("-H | Enable full header encryption. Requires supernode with fixed community.\n");
|
||||
printf("-z1 or -z | Enable lzo1x compression for outgoing data packets\n");
|
||||
#ifdef N2N_HAVE_ZSTD
|
||||
printf("-z2 | Enable zstd compression for outgoing data packets\n");
|
||||
|
@ -393,6 +394,14 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e
|
|||
break;
|
||||
}
|
||||
|
||||
case 'H': /* indicate header encryption */
|
||||
{
|
||||
/* we cannot be sure if this gets parsed before the community name is set.
|
||||
* so, only an indicator is set, action is taken later*/
|
||||
conf->header_encryption = HEADER_ENCRYPTION_ENABLED;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'z':
|
||||
{
|
||||
int compression;
|
||||
|
@ -551,7 +560,7 @@ static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_priv_c
|
|||
u_char c;
|
||||
|
||||
while((c = getopt_long(argc, argv,
|
||||
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z::A::"
|
||||
"k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:SDL:z::A::H"
|
||||
#ifdef __linux__
|
||||
"T:n:"
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include "n2n.h"
|
||||
#include "header_encryption.h"
|
||||
|
||||
/* heap allocation for compression as per lzo example doc */
|
||||
#define HEAP_ALLOC(var,size) lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
|
||||
|
@ -254,6 +255,12 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r
|
|||
goto edge_init_error;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
}
|
||||
|
||||
if(eee->transop.no_encryption)
|
||||
traceEvent(TRACE_WARNING, "Encryption is disabled in edge");
|
||||
|
||||
|
@ -735,6 +742,9 @@ static void send_register_super(n2n_edge_t * eee,
|
|||
traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s",
|
||||
sock_to_cstr(sockbuf, supernode));
|
||||
|
||||
if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
|
||||
|
||||
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, supernode);
|
||||
}
|
||||
|
||||
|
@ -763,6 +773,9 @@ static void send_query_peer( n2n_edge_t * eee,
|
|||
|
||||
traceEvent( TRACE_DEBUG, "send QUERY_PEER to supernode" );
|
||||
|
||||
if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
|
||||
|
||||
sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) );
|
||||
}
|
||||
|
||||
|
@ -806,6 +819,9 @@ static void send_register(n2n_edge_t * eee,
|
|||
traceEvent(TRACE_INFO, "Send REGISTER to %s",
|
||||
sock_to_cstr(sockbuf, remote_peer));
|
||||
|
||||
if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
|
||||
|
||||
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer);
|
||||
}
|
||||
|
||||
|
@ -845,6 +861,8 @@ static void send_register_ack(n2n_edge_t * eee,
|
|||
traceEvent(TRACE_INFO, "send REGISTER_ACK %s",
|
||||
sock_to_cstr(sockbuf, remote_peer));
|
||||
|
||||
if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
|
||||
|
||||
/* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer);
|
||||
}
|
||||
|
@ -1441,6 +1459,9 @@ static void send_packet2net(n2n_edge_t * eee,
|
|||
idx=0;
|
||||
encode_PACKET(pktbuf, &idx, &cmn, &pkt);
|
||||
|
||||
if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx);
|
||||
|
||||
idx += eee->transop.fwd(&eee->transop,
|
||||
pktbuf+idx, N2N_PKT_BUF_SIZE-idx,
|
||||
tap_pkt, len, pkt.dstMac);
|
||||
|
@ -1566,6 +1587,12 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
|
|||
traceEvent(TRACE_DEBUG, "### Rx N2N UDP (%d) from %s",
|
||||
(signed int)recvlen, sock_to_cstr(sockbuf1, &sender));
|
||||
|
||||
if (eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
if ( packet_header_decrypt (udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx) < 0) {
|
||||
traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* hexdump(udp_buf, recvlen); */
|
||||
|
||||
rem = recvlen; /* Counts down bytes of packet to protect against buffer overruns. */
|
||||
|
@ -2346,6 +2373,7 @@ void edge_init_conf_defaults(n2n_edge_conf_t *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;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
/* ********************************************************************** */
|
||||
|
||||
uint32_t packet_header_decrypt (uint8_t packet[], uint8_t packet_len,
|
||||
uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
|
||||
char * community_name, he_context_t * ctx) {
|
||||
|
||||
// assemble IV
|
||||
|
@ -33,18 +33,19 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint8_t packet_len,
|
|||
// the first 96 bits of the packet get padded with ASCII "n2n!"
|
||||
// to full 128 bit IV
|
||||
memcpy (iv, packet, 12);
|
||||
// alternatively, consider: pearson_hash_128 (iv, packet, 12);
|
||||
|
||||
// try community name as possible key and check for magic bytes
|
||||
uint32_t magic = 0x6E326E00; // ="n2n_"
|
||||
uint32_t test_magic;
|
||||
// check for magic bytes and resonable value in header len field
|
||||
// check for magic bytes and reasonable value in header len field
|
||||
// so, as a first step, decrypt 4 bytes only starting at byte 12
|
||||
speck_he ((uint8_t*)&test_magic, &packet[12], 4, iv, (speck_context_t*)ctx);
|
||||
test_magic = be32toh (test_magic);
|
||||
if ( ((test_magic << 8) == magic)
|
||||
&& ((test_magic >> 24) <= packet_len) // (test_masgic >> 24) is header_len
|
||||
if ( (((test_magic >> 8) << 8) == magic) // check the thre uppermost bytes
|
||||
&& (((uint8_t)test_magic) <= packet_len) // lowest 8 bit of test_magic are header_len
|
||||
) {
|
||||
speck_he (&packet[12], &packet[12], (test_magic >> 24) - 12, iv, (speck_context_t*)ctx);
|
||||
// decrypt the complete header
|
||||
speck_he (&packet[12], &packet[12], (uint8_t)(test_magic) - 12, iv, (speck_context_t*)ctx);
|
||||
// restore original packet order
|
||||
memcpy (&packet[0], &packet[16], 4);
|
||||
memcpy (&packet[4], community_name, N2N_COMMUNITY_SIZE);
|
||||
|
@ -55,89 +56,38 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint8_t packet_len,
|
|||
|
||||
/* ********************************************************************** */
|
||||
|
||||
int8_t packet_header_decrypt_if_required (uint8_t packet[], uint16_t packet_len,
|
||||
struct sn_community *communities) {
|
||||
|
||||
struct sn_community *c, *tmp;
|
||||
|
||||
|
||||
if (packet_len < 20)
|
||||
return (-1);
|
||||
|
||||
// first, check if header is unenrypted to put it into the fast-lane then
|
||||
|
||||
// the following check is around 99.99962 percent reliable
|
||||
// it heavily relies on the structure of packet's common part
|
||||
// changes to wire.c:encode/decode_common need to go together with this code
|
||||
if ( (packet[19] == (uint8_t)0x00) // null terminated community name
|
||||
&& (packet[00] == N2N_PKT_VERSION) // correct packet version
|
||||
// && (packet[01] <= N2N_DEFAULT_TTL) // reasonable TTL -- might interfere with hole-punching-related or cli passed higher values ?!
|
||||
&& ((be16toh (*(uint16_t*)&(packet[02])) & N2N_FLAGS_TYPE_MASK ) <= MSG_TYPE_MAX_TYPE ) // message type
|
||||
&& ( be16toh (*(uint16_t*)&(packet[02])) < N2N_FLAGS_OPTIONS) // flags
|
||||
) {
|
||||
|
||||
// most probably unencrypted
|
||||
|
||||
// make sure, no downgrading happens here and no unencrypted packets can be
|
||||
// injected in a community which definitely deals with encrypted headers
|
||||
HASH_FIND_COMMUNITY(communities, (char *)&packet[04], c);
|
||||
if (!c)
|
||||
if (c->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
return (-2);
|
||||
// set 'no encryption' in case it is not set yet
|
||||
c->header_encryption = HEADER_ENCRYPTION_NONE;
|
||||
c->header_encryption_ctx = NULL;
|
||||
return (HEADER_ENCRYPTION_NONE);
|
||||
} else {
|
||||
|
||||
// most probably encrypted
|
||||
// cycle through the known communities (as keys) to eventually decrypt
|
||||
int32_t ret;
|
||||
HASH_ITER (hh, communities, c, tmp) {
|
||||
// skip the definitely unencrypted communities
|
||||
if (c->header_encryption == HEADER_ENCRYPTION_NONE)
|
||||
continue;
|
||||
if ( (ret = packet_header_decrypt (packet, packet_len, c->community, c->header_encryption_ctx)) ) {
|
||||
// set 'encrypted' in case it is not set yet
|
||||
c->header_encryption = HEADER_ENCRYPTION_ENABLED;
|
||||
// no need to test further communities
|
||||
return (HEADER_ENCRYPTION_ENABLED);
|
||||
}
|
||||
}
|
||||
// no matching key/community
|
||||
return (-3);
|
||||
}
|
||||
}
|
||||
|
||||
/* ********************************************************************** */
|
||||
|
||||
int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx) {
|
||||
uint8_t iv[16];
|
||||
uint64_t *iv64 = (uint64_t*)&iv;
|
||||
const uint32_t magic = 0x006E326E;
|
||||
|
||||
if (header_len < 20)
|
||||
uint8_t iv[16];
|
||||
uint32_t *iv32 = (uint32_t*)&iv;
|
||||
uint64_t *iv64 = (uint64_t*)&iv;
|
||||
const uint32_t magic = 0x6E326E21; // = ASCII "n2n!"
|
||||
|
||||
if (header_len < 20) {
|
||||
traceEvent(TRACE_DEBUG, "packet_header_encrypt dropped a packet too short to be valid.");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy (&packet[16], &packet[00], 4);
|
||||
|
||||
iv64[0] = n2n_rand();
|
||||
iv64[1] = n2n_rand();
|
||||
iv64[3] = htobe32(magic);
|
||||
iv[12] = header_len;
|
||||
|
||||
iv64[0] = n2n_rand ();
|
||||
iv32[2] = n2n_rand ();
|
||||
iv32[3] = htobe32 (magic);
|
||||
|
||||
memcpy (packet, iv, 16);
|
||||
packet[15] = header_len;
|
||||
|
||||
speck_he (&packet[12], &packet[12], header_len - 12, iv, (speck_context_t*)ctx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ********************************************************************** */
|
||||
|
||||
void packet_header_setup_key (char * community_name, he_context_t * ctx) {
|
||||
void packet_header_setup_key (const char * community_name, he_context_t ** ctx) {
|
||||
|
||||
uint8_t key[16];
|
||||
pearson_hash_128 (key, (uint8_t*)community_name, N2N_COMMUNITY_SIZE);
|
||||
|
||||
ctx = calloc(1, sizeof(speck_context_t));
|
||||
speck_expand_key_he (key, (speck_context_t*)ctx);
|
||||
*ctx = (he_context_t*)calloc(1, sizeof (speck_context_t));
|
||||
speck_expand_key_he (key, (speck_context_t*)*ctx);
|
||||
}
|
||||
|
|
216
src/sn.c
216
src/sn.c
|
@ -33,12 +33,14 @@
|
|||
#define HASH_FIND_COMMUNITY(head,name,out) HASH_FIND_STR(head,name,out)
|
||||
|
||||
static int try_forward(n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t dstMac,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize);
|
||||
|
||||
static int try_broadcast(n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t srcMac,
|
||||
const uint8_t * pktbuf,
|
||||
|
@ -188,24 +190,17 @@ static ssize_t sendto_sock(n2n_sn_t * sss,
|
|||
}
|
||||
|
||||
static int try_forward(n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t dstMac,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize)
|
||||
{
|
||||
struct peer_info * scan;
|
||||
struct sn_community *community;
|
||||
macstr_t mac_buf;
|
||||
n2n_sock_str_t sockbuf;
|
||||
|
||||
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);
|
||||
HASH_FIND_PEER(comm->edges, dstMac, scan);
|
||||
|
||||
if(NULL != scan)
|
||||
{
|
||||
|
@ -248,51 +243,44 @@ static int try_forward(n2n_sn_t * sss,
|
|||
* the supernode.
|
||||
*/
|
||||
static int try_broadcast(n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t srcMac,
|
||||
const uint8_t * pktbuf,
|
||||
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_FIND_COMMUNITY(sss->communities, (char*)cmn->community, community);
|
||||
HASH_ITER(hh, comm->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;
|
||||
|
||||
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);
|
||||
|
||||
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
|
||||
|
||||
if(data_sent_len != pktsize)
|
||||
{
|
||||
++(sss->stats.errors);
|
||||
traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr),
|
||||
strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
++(sss->stats.broadcast);
|
||||
traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr));
|
||||
}
|
||||
if(data_sent_len != pktsize)
|
||||
{
|
||||
++(sss->stats.errors);
|
||||
traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr),
|
||||
strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
++(sss->stats.broadcast);
|
||||
traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr));
|
||||
}
|
||||
}
|
||||
} else
|
||||
traceEvent(TRACE_INFO, "ignoring broadcast on unknown community %s\n",
|
||||
cmn->community);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -420,7 +408,7 @@ static int load_allowed_sn_community(n2n_sn_t *sss, char *path) {
|
|||
/* we do not know if header encryption is used in this community,
|
||||
* first packet will show. just in case, setup the key. */
|
||||
s->header_encryption = HEADER_ENCRYPTION_UNKNOWN;
|
||||
packet_header_setup_key (s->community, s->header_encryption_ctx);
|
||||
packet_header_setup_key (s->community, &(s->header_encryption_ctx));
|
||||
HASH_ADD_STR(sss->communities, community, s);
|
||||
|
||||
num_communities++;
|
||||
|
@ -452,21 +440,75 @@ static int process_udp(n2n_sn_t * sss,
|
|||
n2n_common_t cmn; /* common fields in the packet header */
|
||||
size_t rem;
|
||||
size_t idx;
|
||||
int8_t he = HEADER_ENCRYPTION_UNKNOWN;
|
||||
size_t msg_type;
|
||||
uint8_t from_supernode;
|
||||
macstr_t mac_buf;
|
||||
macstr_t mac_buf2;
|
||||
n2n_sock_str_t sockbuf;
|
||||
char buf[32];
|
||||
struct sn_community *comm, *tmp;
|
||||
|
||||
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)),
|
||||
ntohs(sender_sock->sin_port));
|
||||
|
||||
he = packet_header_decrypt_if_required (udp_buf, udp_size, sss->communities);
|
||||
if (he < 0)
|
||||
return -1; /* something wrong during packet decryption */
|
||||
/* check if header is unenrypted. the following check is around 99.99962 percent reliable.
|
||||
* it heavily relies on the structure of packet's common part
|
||||
* changes to wire.c:encode/decode_common need to go together with this code */
|
||||
if (udp_size < 20) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp dropped a packet too short to be valid.");
|
||||
return -1;
|
||||
}
|
||||
if ( (udp_buf[19] == (uint8_t)0x00) // null terminated community name
|
||||
&& (udp_buf[00] == N2N_PKT_VERSION) // correct packet version
|
||||
&& ((be16toh (*(uint16_t*)&(udp_buf[02])) & N2N_FLAGS_TYPE_MASK ) <= MSG_TYPE_MAX_TYPE ) // message type
|
||||
&& ( be16toh (*(uint16_t*)&(udp_buf[02])) < N2N_FLAGS_OPTIONS) // flags
|
||||
) {
|
||||
/* most probably unencrypted */
|
||||
/* make sure, no downgrading happens here and no unencrypted packets can be
|
||||
* injected in a community which definitely deals with encrypted headers */
|
||||
HASH_FIND_COMMUNITY(sss->communities, (char *)&udp_buf[04], comm);
|
||||
if (comm) {
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp dropped a packet with unencrypted header "
|
||||
"addressed to community '%s' which uses encrypted headers.",
|
||||
comm->community);
|
||||
return -1;
|
||||
}
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) {
|
||||
traceEvent (TRACE_INFO, "process_udp locked community '%s' to using "
|
||||
"unencrypted headers.", comm->community);
|
||||
/* set 'no encryption' in case it is not set yet */
|
||||
comm->header_encryption = HEADER_ENCRYPTION_NONE;
|
||||
comm->header_encryption_ctx = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* most probably encrypted */
|
||||
/* cycle through the known communities (as keys) to eventually decrypt */
|
||||
uint32_t ret = 0;
|
||||
HASH_ITER (hh, sss->communities, comm, tmp) {
|
||||
/* skip the definitely unencrypted communities */
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_NONE)
|
||||
continue;
|
||||
if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx)) ) {
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) {
|
||||
traceEvent (TRACE_INFO, "process_udp locked community '%s' to using "
|
||||
"encrypted headers.", comm->community);
|
||||
/* set 'encrypted' in case it is not set yet */
|
||||
comm->header_encryption = HEADER_ENCRYPTION_ENABLED;
|
||||
}
|
||||
// no need to test further communities
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ret) {
|
||||
// no matching key/community
|
||||
traceEvent(TRACE_DEBUG, "process_udp dropped a packet with seemingly encrypted header "
|
||||
"for which no matching community which uses encrypted headers was found.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use decode_common() to determine the kind of packet then process it:
|
||||
*
|
||||
|
@ -506,8 +548,12 @@ static int process_udp(n2n_sn_t * sss,
|
|||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx=0;
|
||||
int unicast; /* non-zero if unicast */
|
||||
const uint8_t * rec_buf; /* either udp_buf or encbuf */
|
||||
uint8_t * rec_buf; /* either udp_buf or encbuf */
|
||||
|
||||
if(!comm) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp PACKET with unknown community %s", cmn.community);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sss->stats.last_fwd=now;
|
||||
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
|
||||
|
@ -535,6 +581,9 @@ static int process_udp(n2n_sn_t * sss,
|
|||
/* Re-encode the header. */
|
||||
encode_PACKET(encbuf, &encx, &cmn2, &pkt);
|
||||
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (rec_buf, encx, comm->header_encryption_ctx);
|
||||
|
||||
/* Copy the original payload unchanged */
|
||||
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
|
||||
} else {
|
||||
|
@ -545,13 +594,16 @@ static int process_udp(n2n_sn_t * sss,
|
|||
|
||||
rec_buf = udp_buf;
|
||||
encx = udp_size;
|
||||
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx);
|
||||
}
|
||||
|
||||
/* Common section to forward the final product. */
|
||||
if(unicast)
|
||||
try_forward(sss, &cmn, pkt.dstMac, rec_buf, encx);
|
||||
try_forward(sss, comm, &cmn, pkt.dstMac, rec_buf, encx);
|
||||
else
|
||||
try_broadcast(sss, &cmn, pkt.srcMac, rec_buf, encx);
|
||||
try_broadcast(sss, comm, &cmn, pkt.srcMac, rec_buf, encx);
|
||||
break;
|
||||
}
|
||||
case MSG_TYPE_REGISTER:
|
||||
|
@ -563,7 +615,12 @@ static int process_udp(n2n_sn_t * sss,
|
|||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx=0;
|
||||
int unicast; /* non-zero if unicast */
|
||||
const uint8_t * rec_buf; /* either udp_buf or encbuf */
|
||||
uint8_t * rec_buf; /* either udp_buf or encbuf */
|
||||
|
||||
if(!comm) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp REGISTER from unknown community %s", cmn.community);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sss->stats.last_fwd=now;
|
||||
decode_REGISTER(®, &cmn, udp_buf, &rem, &idx);
|
||||
|
@ -601,7 +658,10 @@ static int process_udp(n2n_sn_t * sss,
|
|||
encx = udp_size;
|
||||
}
|
||||
|
||||
try_forward(sss, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx);
|
||||
|
||||
try_forward(sss, comm, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */
|
||||
} else
|
||||
traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination");
|
||||
break;
|
||||
|
@ -616,15 +676,12 @@ 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 *comm;
|
||||
|
||||
/* 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, comm);
|
||||
|
||||
/*
|
||||
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
|
||||
|
@ -672,6 +729,9 @@ static int process_udp(n2n_sn_t * sss,
|
|||
|
||||
encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack);
|
||||
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (ackbuf, encx, comm->header_encryption_ctx);
|
||||
|
||||
sendto(sss->sock, ackbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
|
||||
|
||||
|
@ -682,13 +742,18 @@ static int process_udp(n2n_sn_t * sss,
|
|||
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
|
||||
(char*)cmn.community);
|
||||
break;
|
||||
} case MSG_TYPE_QUERY_PEER: {
|
||||
}
|
||||
case MSG_TYPE_QUERY_PEER: {
|
||||
n2n_QUERY_PEER_t query;
|
||||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx=0;
|
||||
n2n_common_t cmn2;
|
||||
n2n_PEER_INFO_t pi;
|
||||
struct sn_community *community;
|
||||
|
||||
if(!comm) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp QUERY_PEER from unknown community %s", cmn.community);
|
||||
return -1;
|
||||
}
|
||||
|
||||
decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx );
|
||||
|
||||
|
@ -696,36 +761,35 @@ static int process_udp(n2n_sn_t * sss,
|
|||
macaddr_str( mac_buf, query.srcMac ),
|
||||
macaddr_str( mac_buf2, query.targetMac ) );
|
||||
|
||||
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn.community, community);
|
||||
struct peer_info *scan;
|
||||
HASH_FIND_PEER(comm->edges, query.targetMac, scan);
|
||||
|
||||
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;
|
||||
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
|
||||
memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
|
||||
|
||||
if (scan) {
|
||||
cmn2.ttl = N2N_DEFAULT_TTL;
|
||||
cmn2.pc = n2n_peer_info;
|
||||
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
|
||||
memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
|
||||
pi.aflags = 0;
|
||||
memcpy( pi.mac, query.targetMac, sizeof(n2n_mac_t) );
|
||||
pi.sock = scan->sock;
|
||||
|
||||
pi.aflags = 0;
|
||||
memcpy( pi.mac, query.targetMac, sizeof(n2n_mac_t) );
|
||||
pi.sock = scan->sock;
|
||||
encode_PEER_INFO( encbuf, &encx, &cmn2, &pi );
|
||||
|
||||
encode_PEER_INFO( encbuf, &encx, &cmn2, &pi );
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx);
|
||||
|
||||
sendto( sss->sock, encbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
|
||||
sendto( sss->sock, encbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
|
||||
|
||||
traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s",
|
||||
macaddr_str( mac_buf, query.srcMac ) );
|
||||
} else {
|
||||
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
|
||||
macaddr_str( mac_buf, query.targetMac ) );
|
||||
}
|
||||
traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s",
|
||||
macaddr_str( mac_buf, query.srcMac ) );
|
||||
} else {
|
||||
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
|
||||
macaddr_str( mac_buf, query.targetMac ) );
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Not a known message type */
|
||||
|
|
790
src/sn_utils.c
790
src/sn_utils.c
|
@ -5,22 +5,24 @@
|
|||
#define N2N_SN_LPORT_DEFAULT 7654
|
||||
#define N2N_SN_PKTBUF_SIZE 2048
|
||||
|
||||
static int try_forward(n2n_sn_t *sss,
|
||||
const n2n_common_t *cmn,
|
||||
const n2n_mac_t dstMac,
|
||||
const uint8_t *pktbuf,
|
||||
size_t pktsize);
|
||||
static int try_forward(n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t dstMac,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize);
|
||||
|
||||
static ssize_t sendto_sock(n2n_sn_t *sss,
|
||||
const n2n_sock_t *sock,
|
||||
const uint8_t *pktbuf,
|
||||
size_t pktsize);
|
||||
|
||||
static int try_broadcast(n2n_sn_t *sss,
|
||||
const n2n_common_t *cmn,
|
||||
const n2n_mac_t srcMac,
|
||||
const uint8_t *pktbuf,
|
||||
size_t pktsize);
|
||||
static int try_broadcast(n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t srcMac,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize);
|
||||
|
||||
static uint16_t reg_lifetime(n2n_sn_t *sss);
|
||||
|
||||
|
@ -42,59 +44,51 @@ static int process_udp(n2n_sn_t *sss,
|
|||
size_t udp_size,
|
||||
time_t now);
|
||||
|
||||
static int try_forward(n2n_sn_t *sss,
|
||||
const n2n_common_t *cmn,
|
||||
const n2n_mac_t dstMac,
|
||||
const uint8_t *pktbuf,
|
||||
size_t pktsize)
|
||||
static int try_forward(n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t dstMac,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize)
|
||||
{
|
||||
struct peer_info *scan;
|
||||
struct sn_community *community;
|
||||
macstr_t mac_buf;
|
||||
n2n_sock_str_t sockbuf;
|
||||
struct peer_info * scan;
|
||||
macstr_t mac_buf;
|
||||
n2n_sock_str_t sockbuf;
|
||||
|
||||
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn->community, community);
|
||||
HASH_FIND_PEER(comm->edges, dstMac, scan);
|
||||
|
||||
if (!community)
|
||||
if(NULL != scan)
|
||||
{
|
||||
traceEvent(TRACE_DEBUG, "try_forward unknown community %s", cmn->community);
|
||||
return (-1);
|
||||
}
|
||||
int data_sent_len;
|
||||
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
|
||||
|
||||
HASH_FIND_PEER(community->edges, dstMac, scan);
|
||||
|
||||
if (NULL != scan)
|
||||
{
|
||||
int data_sent_len;
|
||||
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
|
||||
|
||||
if (data_sent_len == pktsize)
|
||||
if(data_sent_len == pktsize)
|
||||
{
|
||||
++(sss->stats.fwd);
|
||||
traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr));
|
||||
++(sss->stats.fwd);
|
||||
traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr));
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
++(sss->stats.errors);
|
||||
traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr),
|
||||
errno, strerror(errno));
|
||||
++(sss->stats.errors);
|
||||
traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr),
|
||||
errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
traceEvent(TRACE_DEBUG, "try_forward unknown MAC");
|
||||
traceEvent(TRACE_DEBUG, "try_forward unknown MAC");
|
||||
|
||||
/* Not a known MAC so drop. */
|
||||
return (-2);
|
||||
/* Not a known MAC so drop. */
|
||||
return(-2);
|
||||
}
|
||||
|
||||
return (0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/** Send a datagram to the destination embodied in a n2n_sock_t.
|
||||
|
@ -136,59 +130,49 @@ static ssize_t sendto_sock(n2n_sn_t *sss,
|
|||
* This will send the exact same datagram to zero or more edges registered to
|
||||
* the supernode.
|
||||
*/
|
||||
static int try_broadcast(n2n_sn_t *sss,
|
||||
const n2n_common_t *cmn,
|
||||
const n2n_mac_t srcMac,
|
||||
const uint8_t *pktbuf,
|
||||
size_t pktsize)
|
||||
static int try_broadcast(n2n_sn_t * sss,
|
||||
const struct sn_community *comm,
|
||||
const n2n_common_t * cmn,
|
||||
const n2n_mac_t srcMac,
|
||||
const uint8_t * pktbuf,
|
||||
size_t pktsize)
|
||||
{
|
||||
struct peer_info *scan, *tmp;
|
||||
struct sn_community *community;
|
||||
macstr_t mac_buf;
|
||||
n2n_sock_str_t sockbuf;
|
||||
struct peer_info *scan, *tmp;
|
||||
macstr_t mac_buf;
|
||||
n2n_sock_str_t sockbuf;
|
||||
|
||||
traceEvent(TRACE_DEBUG, "try_broadcast");
|
||||
traceEvent(TRACE_DEBUG, "try_broadcast");
|
||||
|
||||
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn->community, community);
|
||||
HASH_ITER(hh, comm->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;
|
||||
|
||||
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);
|
||||
|
||||
data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
|
||||
|
||||
if (data_sent_len != pktsize)
|
||||
{
|
||||
++(sss->stats.errors);
|
||||
traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr),
|
||||
strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
++(sss->stats.broadcast);
|
||||
traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(data_sent_len != pktsize)
|
||||
{
|
||||
++(sss->stats.errors);
|
||||
traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr),
|
||||
strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
++(sss->stats.broadcast);
|
||||
traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s",
|
||||
pktsize,
|
||||
sock_to_cstr(sockbuf, &(scan->sock)),
|
||||
macaddr_str(mac_buf, scan->mac_addr));
|
||||
}
|
||||
}
|
||||
else
|
||||
traceEvent(TRACE_INFO, "ignoring broadcast on unknown community %s\n",
|
||||
cmn->community);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/** Initialise the supernode structure */
|
||||
int sn_init(n2n_sn_t *sss)
|
||||
{
|
||||
|
@ -373,316 +357,372 @@ static int process_mgmt(n2n_sn_t *sss,
|
|||
/** Examine a datagram and determine what to do with it.
|
||||
*
|
||||
*/
|
||||
static int process_udp(n2n_sn_t *sss,
|
||||
const struct sockaddr_in *sender_sock,
|
||||
uint8_t *udp_buf,
|
||||
size_t udp_size,
|
||||
time_t now)
|
||||
static int process_udp(n2n_sn_t * sss,
|
||||
const struct sockaddr_in * sender_sock,
|
||||
uint8_t * udp_buf,
|
||||
size_t udp_size,
|
||||
time_t now)
|
||||
{
|
||||
n2n_common_t cmn; /* common fields in the packet header */
|
||||
size_t rem;
|
||||
size_t idx;
|
||||
int8_t he = HEADER_ENCRYPTION_UNKNOWN;
|
||||
size_t msg_type;
|
||||
uint8_t from_supernode;
|
||||
macstr_t mac_buf;
|
||||
macstr_t mac_buf2;
|
||||
n2n_sock_str_t sockbuf;
|
||||
char buf[32];
|
||||
n2n_common_t cmn; /* common fields in the packet header */
|
||||
size_t rem;
|
||||
size_t idx;
|
||||
size_t msg_type;
|
||||
uint8_t from_supernode;
|
||||
macstr_t mac_buf;
|
||||
macstr_t mac_buf2;
|
||||
n2n_sock_str_t sockbuf;
|
||||
char buf[32];
|
||||
struct sn_community *comm, *tmp;
|
||||
|
||||
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)),
|
||||
ntohs(sender_sock->sin_port));
|
||||
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)),
|
||||
ntohs(sender_sock->sin_port));
|
||||
|
||||
he = packet_header_decrypt_if_required (udp_buf, udp_size, sss->communities);
|
||||
if (he < 0)
|
||||
return -1; /* something wrong during packet decryption */
|
||||
|
||||
/* Use decode_common() to determine the kind of packet then process it:
|
||||
*
|
||||
* REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK
|
||||
*
|
||||
* REGISTER, REGISTER_ACK and PACKET messages are forwarded to their
|
||||
* destination edge. If the destination is not known then PACKETs are
|
||||
* broadcast.
|
||||
*/
|
||||
|
||||
rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */
|
||||
idx = 0; /* marches through packet header as parts are decoded. */
|
||||
if (decode_common(&cmn, udp_buf, &rem, &idx) < 0)
|
||||
{
|
||||
traceEvent(TRACE_ERROR, "Failed to decode common section");
|
||||
return -1; /* failed to decode packet */
|
||||
/* check if header is unenrypted. the following check is around 99.99962 percent reliable.
|
||||
* it heavily relies on the structure of packet's common part
|
||||
* changes to wire.c:encode/decode_common need to go together with this code */
|
||||
if (udp_size < 20) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp dropped a packet too short to be valid.");
|
||||
return -1;
|
||||
}
|
||||
if ( (udp_buf[19] == (uint8_t)0x00) // null terminated community name
|
||||
&& (udp_buf[00] == N2N_PKT_VERSION) // correct packet version
|
||||
&& ((be16toh (*(uint16_t*)&(udp_buf[02])) & N2N_FLAGS_TYPE_MASK ) <= MSG_TYPE_MAX_TYPE ) // message type
|
||||
&& ( be16toh (*(uint16_t*)&(udp_buf[02])) < N2N_FLAGS_OPTIONS) // flags
|
||||
) {
|
||||
/* most probably unencrypted */
|
||||
/* make sure, no downgrading happens here and no unencrypted packets can be
|
||||
* injected in a community which definitely deals with encrypted headers */
|
||||
HASH_FIND_COMMUNITY(sss->communities, (char *)&udp_buf[04], comm);
|
||||
if (comm) {
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp dropped a packet with unencrypted header "
|
||||
"addressed to community '%s' which uses encrypted headers.",
|
||||
comm->community);
|
||||
return -1;
|
||||
}
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) {
|
||||
traceEvent (TRACE_INFO, "process_udp locked community '%s' to using "
|
||||
"unencrypted headers.", comm->community);
|
||||
/* set 'no encryption' in case it is not set yet */
|
||||
comm->header_encryption = HEADER_ENCRYPTION_NONE;
|
||||
comm->header_encryption_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
msg_type = cmn.pc; /* packet code */
|
||||
from_supernode = cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
|
||||
|
||||
if (cmn.ttl < 1)
|
||||
{
|
||||
traceEvent(TRACE_WARNING, "Expired TTL");
|
||||
return 0; /* Don't process further */
|
||||
}
|
||||
|
||||
--(cmn.ttl); /* The value copied into all forwarded packets. */
|
||||
|
||||
switch (msg_type)
|
||||
{
|
||||
case MSG_TYPE_PACKET:
|
||||
{
|
||||
/* PACKET from one edge to another edge via supernode. */
|
||||
|
||||
/* pkt will be modified in place and recoded to an output of potentially
|
||||
* different size due to addition of the socket.*/
|
||||
n2n_PACKET_t pkt;
|
||||
n2n_common_t cmn2;
|
||||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx = 0;
|
||||
int unicast; /* non-zero if unicast */
|
||||
const uint8_t *rec_buf; /* either udp_buf or encbuf */
|
||||
|
||||
sss->stats.last_fwd = now;
|
||||
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
|
||||
|
||||
unicast = (0 == is_multi_broadcast(pkt.dstMac));
|
||||
|
||||
traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s",
|
||||
(unicast ? "unicast" : "multicast"),
|
||||
macaddr_str(mac_buf, pkt.srcMac),
|
||||
macaddr_str(mac_buf2, pkt.dstMac),
|
||||
(from_supernode ? "from sn" : "local"));
|
||||
|
||||
if (!from_supernode)
|
||||
{
|
||||
memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
|
||||
|
||||
/* We are going to add socket even if it was not there before */
|
||||
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
|
||||
|
||||
pkt.sock.family = AF_INET;
|
||||
pkt.sock.port = ntohs(sender_sock->sin_port);
|
||||
memcpy(pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
|
||||
|
||||
rec_buf = encbuf;
|
||||
|
||||
/* Re-encode the header. */
|
||||
encode_PACKET(encbuf, &encx, &cmn2, &pkt);
|
||||
|
||||
/* Copy the original payload unchanged */
|
||||
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
|
||||
} else {
|
||||
/* most probably encrypted */
|
||||
/* cycle through the known communities (as keys) to eventually decrypt */
|
||||
uint32_t ret = 0;
|
||||
HASH_ITER (hh, sss->communities, comm, tmp) {
|
||||
/* skip the definitely unencrypted communities */
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_NONE)
|
||||
continue;
|
||||
if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx)) ) {
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_UNKNOWN) {
|
||||
traceEvent (TRACE_INFO, "process_udp locked community '%s' to using "
|
||||
"encrypted headers.", comm->community);
|
||||
/* set 'encrypted' in case it is not set yet */
|
||||
comm->header_encryption = HEADER_ENCRYPTION_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Already from a supernode. Nothing to modify, just pass to
|
||||
* destination. */
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Rx PACKET fwd unmodified");
|
||||
|
||||
rec_buf = udp_buf;
|
||||
encx = udp_size;
|
||||
}
|
||||
|
||||
/* Common section to forward the final product. */
|
||||
if (unicast)
|
||||
try_forward(sss, &cmn, pkt.dstMac, rec_buf, encx);
|
||||
else
|
||||
try_broadcast(sss, &cmn, pkt.srcMac, rec_buf, encx);
|
||||
// no need to test further communities
|
||||
break;
|
||||
}
|
||||
}
|
||||
case MSG_TYPE_REGISTER:
|
||||
{
|
||||
/* Forwarding a REGISTER from one edge to the next */
|
||||
|
||||
n2n_REGISTER_t reg;
|
||||
n2n_common_t cmn2;
|
||||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx = 0;
|
||||
int unicast; /* non-zero if unicast */
|
||||
const uint8_t *rec_buf; /* either udp_buf or encbuf */
|
||||
|
||||
sss->stats.last_fwd = now;
|
||||
decode_REGISTER(®, &cmn, udp_buf, &rem, &idx);
|
||||
|
||||
unicast = (0 == is_multi_broadcast(reg.dstMac));
|
||||
|
||||
if (unicast)
|
||||
{
|
||||
traceEvent(TRACE_DEBUG, "Rx REGISTER %s -> %s %s",
|
||||
macaddr_str(mac_buf, reg.srcMac),
|
||||
macaddr_str(mac_buf2, reg.dstMac),
|
||||
((cmn.flags & N2N_FLAGS_FROM_SUPERNODE) ? "from sn" : "local"));
|
||||
|
||||
if (0 == (cmn.flags & N2N_FLAGS_FROM_SUPERNODE))
|
||||
{
|
||||
memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
|
||||
|
||||
/* We are going to add socket even if it was not there before */
|
||||
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
|
||||
|
||||
reg.sock.family = AF_INET;
|
||||
reg.sock.port = ntohs(sender_sock->sin_port);
|
||||
memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
|
||||
|
||||
rec_buf = encbuf;
|
||||
|
||||
/* Re-encode the header. */
|
||||
encode_REGISTER(encbuf, &encx, &cmn2, ®);
|
||||
|
||||
/* Copy the original payload unchanged */
|
||||
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Already from a supernode. Nothing to modify, just pass to
|
||||
* destination. */
|
||||
|
||||
rec_buf = udp_buf;
|
||||
encx = udp_size;
|
||||
}
|
||||
|
||||
try_forward(sss, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */
|
||||
}
|
||||
else
|
||||
traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination");
|
||||
break;
|
||||
if (!ret) {
|
||||
// no matching key/community
|
||||
traceEvent(TRACE_DEBUG, "process_udp dropped a packet with seemingly encrypted header "
|
||||
"for which no matching community which uses encrypted headers was found.");
|
||||
return -1;
|
||||
}
|
||||
case MSG_TYPE_REGISTER_ACK:
|
||||
traceEvent(TRACE_DEBUG, "Rx REGISTER_ACK (NOT IMPLEMENTED) SHould not be via supernode");
|
||||
break;
|
||||
case MSG_TYPE_REGISTER_SUPER:
|
||||
{
|
||||
n2n_REGISTER_SUPER_t reg;
|
||||
n2n_REGISTER_SUPER_ACK_t ack;
|
||||
n2n_common_t cmn2;
|
||||
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx = 0;
|
||||
struct sn_community *comm;
|
||||
}
|
||||
|
||||
/* Edge requesting registration with us. */
|
||||
sss->stats.last_reg_super = now;
|
||||
++(sss->stats.reg_super);
|
||||
decode_REGISTER_SUPER(®, &cmn, udp_buf, &rem, &idx);
|
||||
/* Use decode_common() to determine the kind of packet then process it:
|
||||
*
|
||||
* REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK
|
||||
*
|
||||
* REGISTER, REGISTER_ACK and PACKET messages are forwarded to their
|
||||
* destination edge. If the destination is not known then PACKETs are
|
||||
* broadcast.
|
||||
*/
|
||||
|
||||
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn.community, comm);
|
||||
rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */
|
||||
idx = 0; /* marches through packet header as parts are decoded. */
|
||||
if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) {
|
||||
traceEvent(TRACE_ERROR, "Failed to decode common section");
|
||||
return -1; /* failed to decode packet */
|
||||
}
|
||||
|
||||
/*
|
||||
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 (!comm && !sss->lock_communities)
|
||||
{
|
||||
comm = calloc(1, sizeof(struct sn_community));
|
||||
msg_type = cmn.pc; /* packet code */
|
||||
from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
|
||||
|
||||
if (comm)
|
||||
{
|
||||
strncpy(comm->community, (char *)cmn.community, N2N_COMMUNITY_SIZE - 1);
|
||||
comm->community[N2N_COMMUNITY_SIZE - 1] = '\0';
|
||||
/* new communities introduced by REGISTERs could not have had encrypted header */
|
||||
comm->header_encryption = HEADER_ENCRYPTION_NONE;
|
||||
comm->header_encryption_ctx = NULL;
|
||||
if(cmn.ttl < 1) {
|
||||
traceEvent(TRACE_WARNING, "Expired TTL");
|
||||
return 0; /* Don't process further */
|
||||
}
|
||||
|
||||
HASH_ADD_STR(sss->communities, community, comm);
|
||||
--(cmn.ttl); /* The value copied into all forwarded packets. */
|
||||
|
||||
traceEvent(TRACE_INFO, "New community: %s", comm->community);
|
||||
}
|
||||
}
|
||||
switch(msg_type) {
|
||||
case MSG_TYPE_PACKET:
|
||||
{
|
||||
/* PACKET from one edge to another edge via supernode. */
|
||||
|
||||
if (comm)
|
||||
{
|
||||
cmn2.ttl = N2N_DEFAULT_TTL;
|
||||
cmn2.pc = n2n_register_super_ack;
|
||||
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
|
||||
memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t));
|
||||
/* pkt will be modified in place and recoded to an output of potentially
|
||||
* different size due to addition of the socket.*/
|
||||
n2n_PACKET_t pkt;
|
||||
n2n_common_t cmn2;
|
||||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx=0;
|
||||
int unicast; /* non-zero if unicast */
|
||||
uint8_t * rec_buf; /* either udp_buf or encbuf */
|
||||
|
||||
memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t));
|
||||
memcpy(ack.edgeMac, reg.edgeMac, sizeof(n2n_mac_t));
|
||||
ack.lifetime = reg_lifetime(sss);
|
||||
|
||||
ack.sock.family = AF_INET;
|
||||
ack.sock.port = ntohs(sender_sock->sin_port);
|
||||
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);
|
||||
|
||||
encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack);
|
||||
|
||||
sendto(sss->sock, ackbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]",
|
||||
macaddr_str(mac_buf, reg.edgeMac),
|
||||
sock_to_cstr(sockbuf, &(ack.sock)));
|
||||
}
|
||||
else
|
||||
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
|
||||
(char *)cmn.community);
|
||||
break;
|
||||
if(!comm) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp PACKET with unknown community %s", cmn.community);
|
||||
return -1;
|
||||
}
|
||||
case MSG_TYPE_QUERY_PEER:
|
||||
{
|
||||
n2n_QUERY_PEER_t query;
|
||||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx = 0;
|
||||
n2n_common_t cmn2;
|
||||
n2n_PEER_INFO_t pi;
|
||||
struct sn_community *community;
|
||||
|
||||
decode_QUERY_PEER(&query, &cmn, udp_buf, &rem, &idx);
|
||||
sss->stats.last_fwd=now;
|
||||
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Rx QUERY_PEER from %s for %s",
|
||||
macaddr_str(mac_buf, query.srcMac),
|
||||
macaddr_str(mac_buf2, query.targetMac));
|
||||
unicast = (0 == is_multi_broadcast(pkt.dstMac));
|
||||
|
||||
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn.community, community);
|
||||
traceEvent(TRACE_DEBUG, "RX PACKET (%s) %s -> %s %s",
|
||||
(unicast?"unicast":"multicast"),
|
||||
macaddr_str(mac_buf, pkt.srcMac),
|
||||
macaddr_str(mac_buf2, pkt.dstMac),
|
||||
(from_supernode?"from sn":"local"));
|
||||
|
||||
if (community)
|
||||
{
|
||||
struct peer_info *scan;
|
||||
HASH_FIND_PEER(community->edges, query.targetMac, scan);
|
||||
if(!from_supernode) {
|
||||
memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
|
||||
|
||||
if (scan)
|
||||
{
|
||||
cmn2.ttl = N2N_DEFAULT_TTL;
|
||||
cmn2.pc = n2n_peer_info;
|
||||
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
|
||||
memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t));
|
||||
/* We are going to add socket even if it was not there before */
|
||||
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
|
||||
|
||||
pi.aflags = 0;
|
||||
memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t));
|
||||
pi.sock = scan->sock;
|
||||
pkt.sock.family = AF_INET;
|
||||
pkt.sock.port = ntohs(sender_sock->sin_port);
|
||||
memcpy(pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
|
||||
|
||||
encode_PEER_INFO(encbuf, &encx, &cmn2, &pi);
|
||||
rec_buf = encbuf;
|
||||
|
||||
sendto(sss->sock, encbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
|
||||
/* Re-encode the header. */
|
||||
encode_PACKET(encbuf, &encx, &cmn2, &pkt);
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Tx PEER_INFO to %s",
|
||||
macaddr_str(mac_buf, query.srcMac));
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEvent(TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
|
||||
macaddr_str(mac_buf, query.targetMac));
|
||||
}
|
||||
}
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (rec_buf, encx, comm->header_encryption_ctx);
|
||||
|
||||
break;
|
||||
/* Copy the original payload unchanged */
|
||||
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
|
||||
} else {
|
||||
/* Already from a supernode. Nothing to modify, just pass to
|
||||
* destination. */
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Rx PACKET fwd unmodified");
|
||||
|
||||
rec_buf = udp_buf;
|
||||
encx = udp_size;
|
||||
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx);
|
||||
}
|
||||
default:
|
||||
/* Not a known message type */
|
||||
traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type);
|
||||
} /* switch(msg_type) */
|
||||
|
||||
return 0;
|
||||
/* Common section to forward the final product. */
|
||||
if(unicast)
|
||||
try_forward(sss, comm, &cmn, pkt.dstMac, rec_buf, encx);
|
||||
else
|
||||
try_broadcast(sss, comm, &cmn, pkt.srcMac, rec_buf, encx);
|
||||
break;
|
||||
}
|
||||
case MSG_TYPE_REGISTER:
|
||||
{
|
||||
/* Forwarding a REGISTER from one edge to the next */
|
||||
|
||||
n2n_REGISTER_t reg;
|
||||
n2n_common_t cmn2;
|
||||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx=0;
|
||||
int unicast; /* non-zero if unicast */
|
||||
uint8_t * rec_buf; /* either udp_buf or encbuf */
|
||||
|
||||
if(!comm) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp REGISTER from unknown community %s", cmn.community);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sss->stats.last_fwd=now;
|
||||
decode_REGISTER(®, &cmn, udp_buf, &rem, &idx);
|
||||
|
||||
unicast = (0 == is_multi_broadcast(reg.dstMac));
|
||||
|
||||
if(unicast) {
|
||||
traceEvent(TRACE_DEBUG, "Rx REGISTER %s -> %s %s",
|
||||
macaddr_str(mac_buf, reg.srcMac),
|
||||
macaddr_str(mac_buf2, reg.dstMac),
|
||||
((cmn.flags & N2N_FLAGS_FROM_SUPERNODE)?"from sn":"local"));
|
||||
|
||||
if(0 == (cmn.flags & N2N_FLAGS_FROM_SUPERNODE)) {
|
||||
memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
|
||||
|
||||
/* We are going to add socket even if it was not there before */
|
||||
cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
|
||||
|
||||
reg.sock.family = AF_INET;
|
||||
reg.sock.port = ntohs(sender_sock->sin_port);
|
||||
memcpy(reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE);
|
||||
|
||||
rec_buf = encbuf;
|
||||
|
||||
/* Re-encode the header. */
|
||||
encode_REGISTER(encbuf, &encx, &cmn2, ®);
|
||||
|
||||
/* Copy the original payload unchanged */
|
||||
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
|
||||
} else {
|
||||
/* Already from a supernode. Nothing to modify, just pass to
|
||||
* destination. */
|
||||
|
||||
rec_buf = udp_buf;
|
||||
encx = udp_size;
|
||||
}
|
||||
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx);
|
||||
|
||||
try_forward(sss, comm, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */
|
||||
} else
|
||||
traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination");
|
||||
break;
|
||||
}
|
||||
case MSG_TYPE_REGISTER_ACK:
|
||||
traceEvent(TRACE_DEBUG, "Rx REGISTER_ACK (NOT IMPLEMENTED) SHould not be via supernode");
|
||||
break;
|
||||
case MSG_TYPE_REGISTER_SUPER:
|
||||
{
|
||||
n2n_REGISTER_SUPER_t reg;
|
||||
n2n_REGISTER_SUPER_ACK_t ack;
|
||||
n2n_common_t cmn2;
|
||||
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx=0;
|
||||
|
||||
/* Edge requesting registration with us. */
|
||||
sss->stats.last_reg_super=now;
|
||||
++(sss->stats.reg_super);
|
||||
decode_REGISTER_SUPER(®, &cmn, udp_buf, &rem, &idx);
|
||||
|
||||
/*
|
||||
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(!comm && !sss->lock_communities) {
|
||||
comm = calloc(1, sizeof(struct sn_community));
|
||||
|
||||
if(comm) {
|
||||
strncpy(comm->community, (char*)cmn.community, N2N_COMMUNITY_SIZE-1);
|
||||
comm->community[N2N_COMMUNITY_SIZE-1] = '\0';
|
||||
/* new communities introduced by REGISTERs could not have had encrypted header */
|
||||
comm->header_encryption = HEADER_ENCRYPTION_NONE;
|
||||
comm->header_encryption_ctx = NULL;
|
||||
|
||||
HASH_ADD_STR(sss->communities, community, comm);
|
||||
|
||||
traceEvent(TRACE_INFO, "New community: %s", comm->community);
|
||||
}
|
||||
}
|
||||
|
||||
if(comm) {
|
||||
cmn2.ttl = N2N_DEFAULT_TTL;
|
||||
cmn2.pc = n2n_register_super_ack;
|
||||
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
|
||||
memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t));
|
||||
|
||||
memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t));
|
||||
memcpy(ack.edgeMac, reg.edgeMac, sizeof(n2n_mac_t));
|
||||
ack.lifetime = reg_lifetime(sss);
|
||||
|
||||
ack.sock.family = AF_INET;
|
||||
ack.sock.port = ntohs(sender_sock->sin_port);
|
||||
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);
|
||||
|
||||
encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack);
|
||||
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (ackbuf, encx, comm->header_encryption_ctx);
|
||||
|
||||
sendto(sss->sock, ackbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
|
||||
|
||||
traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]",
|
||||
macaddr_str(mac_buf, reg.edgeMac),
|
||||
sock_to_cstr(sockbuf, &(ack.sock)));
|
||||
} else
|
||||
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
|
||||
(char*)cmn.community);
|
||||
break;
|
||||
}
|
||||
case MSG_TYPE_QUERY_PEER: {
|
||||
n2n_QUERY_PEER_t query;
|
||||
uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
|
||||
size_t encx=0;
|
||||
n2n_common_t cmn2;
|
||||
n2n_PEER_INFO_t pi;
|
||||
|
||||
if(!comm) {
|
||||
traceEvent(TRACE_DEBUG, "process_udp QUERY_PEER from unknown community %s", cmn.community);
|
||||
return -1;
|
||||
}
|
||||
|
||||
decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx );
|
||||
|
||||
traceEvent( TRACE_DEBUG, "Rx QUERY_PEER from %s for %s",
|
||||
macaddr_str( mac_buf, query.srcMac ),
|
||||
macaddr_str( mac_buf2, query.targetMac ) );
|
||||
|
||||
struct peer_info *scan;
|
||||
HASH_FIND_PEER(comm->edges, query.targetMac, scan);
|
||||
|
||||
if (scan) {
|
||||
cmn2.ttl = N2N_DEFAULT_TTL;
|
||||
cmn2.pc = n2n_peer_info;
|
||||
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
|
||||
memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
|
||||
|
||||
pi.aflags = 0;
|
||||
memcpy( pi.mac, query.targetMac, sizeof(n2n_mac_t) );
|
||||
pi.sock = scan->sock;
|
||||
|
||||
encode_PEER_INFO( encbuf, &encx, &cmn2, &pi );
|
||||
|
||||
if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED)
|
||||
packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx);
|
||||
|
||||
sendto( sss->sock, encbuf, encx, 0,
|
||||
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
|
||||
|
||||
traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s",
|
||||
macaddr_str( mac_buf, query.srcMac ) );
|
||||
} else {
|
||||
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
|
||||
macaddr_str( mac_buf, query.targetMac ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Not a known message type */
|
||||
traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type);
|
||||
} /* switch(msg_type) */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Long lived processing entry point. Split out from main to simply
|
||||
|
|
Loading…
Reference in New Issue
Block a user