Browse Source

Merge pull request #271 from Logan007/he

Header Encryption
pull/275/head
Luca Deri 4 years ago
committed by GitHub
parent
commit
a5dc46af30
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      include/header_encryption.h
  2. 5
      include/n2n_define.h
  3. 13
      src/edge.c
  4. 28
      src/edge_utils.c
  5. 92
      src/header_encryption.c
  6. 140
      src/sn.c
  7. 196
      src/sn_utils.c

12
include/header_encryption.h

@ -17,19 +17,11 @@
*/ */
uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len,
/* 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,
char * community_name, he_context_t * ctx); 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); 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);

5
include/n2n_define.h

@ -60,6 +60,11 @@
bits of transform_id; will be obsolete as soon as compression gets bits of transform_id; will be obsolete as soon as compression gets
its own field in the packet. REVISIT then. */ 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 DEFAULT_MTU 1290
#define HASH_ADD_PEER(head,add) \ #define HASH_ADD_PEER(head,add) \

13
src/edge.c

@ -154,7 +154,7 @@ static void help() {
#ifndef __APPLE__ #ifndef __APPLE__
"[-D] " "[-D] "
#endif #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) #if defined(N2N_CAN_NAME_IFACE)
printf("-d <tun device> | tun device name\n"); 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"); printf("-A4 | Use ChaCha20 for payload encryption. Requires a key.\n");
#endif #endif
printf("-A5 | Use Speck for payload encryption. Requires a key.\n"); 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"); printf("-z1 or -z | Enable lzo1x compression for outgoing data packets\n");
#ifdef N2N_HAVE_ZSTD #ifdef N2N_HAVE_ZSTD
printf("-z2 | Enable zstd compression for outgoing data packets\n"); 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; 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': case 'z':
{ {
int compression; int compression;
@ -551,7 +560,7 @@ static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_priv_c
u_char c; u_char c;
while((c = getopt_long(argc, argv, 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__ #ifdef __linux__
"T:n:" "T:n:"
#endif #endif

28
src/edge_utils.c

@ -17,6 +17,7 @@
*/ */
#include "n2n.h" #include "n2n.h"
#include "header_encryption.h"
/* heap allocation for compression as per lzo example doc */ /* 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) ] #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; 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) if(eee->transop.no_encryption)
traceEvent(TRACE_WARNING, "Encryption is disabled in edge"); 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", traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s",
sock_to_cstr(sockbuf, supernode)); 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); /* 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" ); 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) ); 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", traceEvent(TRACE_INFO, "Send REGISTER to %s",
sock_to_cstr(sockbuf, remote_peer)); 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); /* 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", traceEvent(TRACE_INFO, "send REGISTER_ACK %s",
sock_to_cstr(sockbuf, remote_peer)); 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); /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer);
} }
@ -1441,6 +1459,9 @@ static void send_packet2net(n2n_edge_t * eee,
idx=0; idx=0;
encode_PACKET(pktbuf, &idx, &cmn, &pkt); 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, idx += eee->transop.fwd(&eee->transop,
pktbuf+idx, N2N_PKT_BUF_SIZE-idx, pktbuf+idx, N2N_PKT_BUF_SIZE-idx,
tap_pkt, len, pkt.dstMac); 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", traceEvent(TRACE_DEBUG, "### Rx N2N UDP (%d) from %s",
(signed int)recvlen, sock_to_cstr(sockbuf1, &sender)); (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); */ /* hexdump(udp_buf, recvlen); */
rem = recvlen; /* Counts down bytes of packet to protect against buffer overruns. */ 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->local_port = 0 /* any port */;
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */ conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
conf->transop_id = N2N_TRANSFORM_ID_NULL; conf->transop_id = N2N_TRANSFORM_ID_NULL;
conf->header_encryption = HEADER_ENCRYPTION_NONE;
conf->compression = N2N_COMPRESSION_ID_NONE; conf->compression = N2N_COMPRESSION_ID_NONE;
conf->drop_multicast = 1; conf->drop_multicast = 1;
conf->allow_p2p = 1; conf->allow_p2p = 1;

92
src/header_encryption.c

@ -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) { char * community_name, he_context_t * ctx) {
// assemble IV // 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!" // the first 96 bits of the packet get padded with ASCII "n2n!"
// to full 128 bit IV // to full 128 bit IV
memcpy (iv, packet, 12); memcpy (iv, packet, 12);
// alternatively, consider: pearson_hash_128 (iv, packet, 12);
// try community name as possible key and check for magic bytes // try community name as possible key and check for magic bytes
uint32_t magic = 0x6E326E00; // ="n2n_" uint32_t magic = 0x6E326E00; // ="n2n_"
uint32_t test_magic; 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); speck_he ((uint8_t*)&test_magic, &packet[12], 4, iv, (speck_context_t*)ctx);
test_magic = be32toh (test_magic); test_magic = be32toh (test_magic);
if ( ((test_magic << 8) == magic) if ( (((test_magic >> 8) << 8) == magic) // check the thre uppermost bytes
&& ((test_magic >> 24) <= packet_len) // (test_masgic >> 24) is header_len && (((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 // restore original packet order
memcpy (&packet[0], &packet[16], 4); memcpy (&packet[0], &packet[16], 4);
memcpy (&packet[4], community_name, N2N_COMMUNITY_SIZE); 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) { int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx) {
uint8_t iv[16]; uint8_t iv[16];
uint32_t *iv32 = (uint32_t*)&iv;
uint64_t *iv64 = (uint64_t*)&iv; uint64_t *iv64 = (uint64_t*)&iv;
const uint32_t magic = 0x006E326E; const uint32_t magic = 0x6E326E21; // = ASCII "n2n!"
if (header_len < 20) if (header_len < 20) {
traceEvent(TRACE_DEBUG, "packet_header_encrypt dropped a packet too short to be valid.");
return (-1); return (-1);
}
memcpy (&packet[16], &packet[00], 4); memcpy (&packet[16], &packet[00], 4);
iv64[0] = n2n_rand (); iv64[0] = n2n_rand ();
iv64[1] = n2n_rand(); iv32[2] = n2n_rand ();
iv64[3] = htobe32(magic); iv32[3] = htobe32 (magic);
iv[12] = header_len;
speck_he (&packet[12], &packet[12], header_len - 12, iv, (speck_context_t*)ctx); memcpy (packet, iv, 16);
packet[15] = header_len;
speck_he (&packet[12], &packet[12], header_len - 12, iv, (speck_context_t*)ctx);
return (0); 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]; uint8_t key[16];
pearson_hash_128 (key, (uint8_t*)community_name, N2N_COMMUNITY_SIZE); pearson_hash_128 (key, (uint8_t*)community_name, N2N_COMMUNITY_SIZE);
ctx = calloc(1, sizeof(speck_context_t)); *ctx = (he_context_t*)calloc(1, sizeof (speck_context_t));
speck_expand_key_he (key, (speck_context_t*)ctx); speck_expand_key_he (key, (speck_context_t*)*ctx);
} }

140
src/sn.c

@ -33,12 +33,14 @@
#define HASH_FIND_COMMUNITY(head,name,out) HASH_FIND_STR(head,name,out) #define HASH_FIND_COMMUNITY(head,name,out) HASH_FIND_STR(head,name,out)
static int try_forward(n2n_sn_t * sss, static int try_forward(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t dstMac, const n2n_mac_t dstMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
size_t pktsize); size_t pktsize);
static int try_broadcast(n2n_sn_t * sss, static int try_broadcast(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t srcMac, const n2n_mac_t srcMac,
const uint8_t * pktbuf, 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, static int try_forward(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t dstMac, const n2n_mac_t dstMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
size_t pktsize) size_t pktsize)
{ {
struct peer_info * scan; struct peer_info * scan;
struct sn_community *community;
macstr_t mac_buf; macstr_t mac_buf;
n2n_sock_str_t sockbuf; n2n_sock_str_t sockbuf;
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn->community, community); HASH_FIND_PEER(comm->edges, dstMac, scan);
if(!community) {
traceEvent(TRACE_DEBUG, "try_forward unknown community %s", cmn->community);
return(-1);
}
HASH_FIND_PEER(community->edges, dstMac, scan);
if(NULL != scan) if(NULL != scan)
{ {
@ -248,22 +243,19 @@ static int try_forward(n2n_sn_t * sss,
* the supernode. * the supernode.
*/ */
static int try_broadcast(n2n_sn_t * sss, static int try_broadcast(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t srcMac, const n2n_mac_t srcMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
size_t pktsize) size_t pktsize)
{ {
struct peer_info *scan, *tmp; struct peer_info *scan, *tmp;
struct sn_community *community;
macstr_t mac_buf; macstr_t mac_buf;
n2n_sock_str_t sockbuf; 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(community) {
HASH_ITER(hh, community->edges, scan, tmp) {
if(memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0) { if(memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) != 0) {
/* REVISIT: exclude if the destination socket is where the packet came from. */ /* REVISIT: exclude if the destination socket is where the packet came from. */
int data_sent_len; int data_sent_len;
@ -289,10 +281,6 @@ static int try_broadcast(n2n_sn_t * sss,
} }
} }
} }
} else
traceEvent(TRACE_INFO, "ignoring broadcast on unknown community %s\n",
cmn->community);
return 0; 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, /* we do not know if header encryption is used in this community,
* first packet will show. just in case, setup the key. */ * first packet will show. just in case, setup the key. */
s->header_encryption = HEADER_ENCRYPTION_UNKNOWN; 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); HASH_ADD_STR(sss->communities, community, s);
num_communities++; num_communities++;
@ -452,21 +440,75 @@ static int process_udp(n2n_sn_t * sss,
n2n_common_t cmn; /* common fields in the packet header */ n2n_common_t cmn; /* common fields in the packet header */
size_t rem; size_t rem;
size_t idx; size_t idx;
int8_t he = HEADER_ENCRYPTION_UNKNOWN;
size_t msg_type; size_t msg_type;
uint8_t from_supernode; uint8_t from_supernode;
macstr_t mac_buf; macstr_t mac_buf;
macstr_t mac_buf2; macstr_t mac_buf2;
n2n_sock_str_t sockbuf; n2n_sock_str_t sockbuf;
char buf[32]; char buf[32];
struct sn_community *comm, *tmp;
traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]", 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)), udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)),
ntohs(sender_sock->sin_port)); ntohs(sender_sock->sin_port));
he = packet_header_decrypt_if_required (udp_buf, udp_size, sss->communities); /* check if header is unenrypted. the following check is around 99.99962 percent reliable.
if (he < 0) * it heavily relies on the structure of packet's common part
return -1; /* something wrong during packet decryption */ * 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: /* 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]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
int unicast; /* non-zero if unicast */ 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; sss->stats.last_fwd=now;
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
@ -535,6 +581,9 @@ static int process_udp(n2n_sn_t * sss,
/* Re-encode the header. */ /* Re-encode the header. */
encode_PACKET(encbuf, &encx, &cmn2, &pkt); 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 */ /* Copy the original payload unchanged */
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx)); encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
} else { } else {
@ -545,13 +594,16 @@ static int process_udp(n2n_sn_t * sss,
rec_buf = udp_buf; rec_buf = udp_buf;
encx = udp_size; 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. */ /* Common section to forward the final product. */
if(unicast) if(unicast)
try_forward(sss, &cmn, pkt.dstMac, rec_buf, encx); try_forward(sss, comm, &cmn, pkt.dstMac, rec_buf, encx);
else else
try_broadcast(sss, &cmn, pkt.srcMac, rec_buf, encx); try_broadcast(sss, comm, &cmn, pkt.srcMac, rec_buf, encx);
break; break;
} }
case MSG_TYPE_REGISTER: case MSG_TYPE_REGISTER:
@ -563,7 +615,12 @@ static int process_udp(n2n_sn_t * sss,
uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
int unicast; /* non-zero if unicast */ 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; sss->stats.last_fwd=now;
decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx);
@ -601,7 +658,10 @@ static int process_udp(n2n_sn_t * sss,
encx = udp_size; 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 } else
traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination"); traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination");
break; break;
@ -616,15 +676,12 @@ static int process_udp(n2n_sn_t * sss,
n2n_common_t cmn2; n2n_common_t cmn2;
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
struct sn_community *comm;
/* Edge requesting registration with us. */ /* Edge requesting registration with us. */
sss->stats.last_reg_super=now; sss->stats.last_reg_super=now;
++(sss->stats.reg_super); ++(sss->stats.reg_super);
decode_REGISTER_SUPER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER_SUPER(&reg, &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 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 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); 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, sendto(sss->sock, ackbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); (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'", traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
(char*)cmn.community); (char*)cmn.community);
break; break;
} case MSG_TYPE_QUERY_PEER: { }
case MSG_TYPE_QUERY_PEER: {
n2n_QUERY_PEER_t query; n2n_QUERY_PEER_t query;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
n2n_common_t cmn2; n2n_common_t cmn2;
n2n_PEER_INFO_t pi; 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 ); decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx );
@ -696,11 +761,8 @@ static int process_udp(n2n_sn_t * sss,
macaddr_str( mac_buf, query.srcMac ), macaddr_str( mac_buf, query.srcMac ),
macaddr_str( mac_buf2, query.targetMac ) ); macaddr_str( mac_buf2, query.targetMac ) );
HASH_FIND_COMMUNITY(sss->communities, (char*)cmn.community, community);
if(community) {
struct peer_info *scan; struct peer_info *scan;
HASH_FIND_PEER(community->edges, query.targetMac, scan); HASH_FIND_PEER(comm->edges, query.targetMac, scan);
if (scan) { if (scan) {
cmn2.ttl = N2N_DEFAULT_TTL; cmn2.ttl = N2N_DEFAULT_TTL;
@ -714,6 +776,9 @@ static int process_udp(n2n_sn_t * sss,
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, sendto( sss->sock, encbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) ); (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
@ -723,7 +788,6 @@ static int process_udp(n2n_sn_t * sss,
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s", traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
macaddr_str( mac_buf, query.targetMac ) ); macaddr_str( mac_buf, query.targetMac ) );
} }
}
break; break;
} }

196
src/sn_utils.c

@ -6,6 +6,7 @@
#define N2N_SN_PKTBUF_SIZE 2048 #define N2N_SN_PKTBUF_SIZE 2048
static int try_forward(n2n_sn_t * sss, static int try_forward(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t dstMac, const n2n_mac_t dstMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
@ -17,6 +18,7 @@ static ssize_t sendto_sock(n2n_sn_t *sss,
size_t pktsize); size_t pktsize);
static int try_broadcast(n2n_sn_t * sss, static int try_broadcast(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t srcMac, const n2n_mac_t srcMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
@ -43,25 +45,17 @@ static int process_udp(n2n_sn_t *sss,
time_t now); time_t now);
static int try_forward(n2n_sn_t * sss, static int try_forward(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t dstMac, const n2n_mac_t dstMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
size_t pktsize) size_t pktsize)
{ {
struct peer_info * scan; struct peer_info * scan;
struct sn_community *community;
macstr_t mac_buf; macstr_t mac_buf;
n2n_sock_str_t sockbuf; n2n_sock_str_t sockbuf;
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn->community, community); HASH_FIND_PEER(comm->edges, dstMac, scan);
if (!community)
{
traceEvent(TRACE_DEBUG, "try_forward unknown community %s", cmn->community);
return (-1);
}
HASH_FIND_PEER(community->edges, dstMac, scan);
if(NULL != scan) if(NULL != scan)
{ {
@ -137,26 +131,20 @@ static ssize_t sendto_sock(n2n_sn_t *sss,
* the supernode. * the supernode.
*/ */
static int try_broadcast(n2n_sn_t * sss, static int try_broadcast(n2n_sn_t * sss,
const struct sn_community *comm,
const n2n_common_t * cmn, const n2n_common_t * cmn,
const n2n_mac_t srcMac, const n2n_mac_t srcMac,
const uint8_t * pktbuf, const uint8_t * pktbuf,
size_t pktsize) size_t pktsize)
{ {
struct peer_info *scan, *tmp; struct peer_info *scan, *tmp;
struct sn_community *community;
macstr_t mac_buf; macstr_t mac_buf;
n2n_sock_str_t sockbuf; 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) {
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. */ /* REVISIT: exclude if the destination socket is where the packet came from. */
int data_sent_len; int data_sent_len;
@ -181,14 +169,10 @@ static int try_broadcast(n2n_sn_t *sss,
} }
} }
} }
}
else
traceEvent(TRACE_INFO, "ignoring broadcast on unknown community %s\n",
cmn->community);
return 0; return 0;
} }
/** Initialise the supernode structure */ /** Initialise the supernode structure */
int sn_init(n2n_sn_t *sss) int sn_init(n2n_sn_t *sss)
{ {
@ -382,21 +366,75 @@ static int process_udp(n2n_sn_t *sss,
n2n_common_t cmn; /* common fields in the packet header */ n2n_common_t cmn; /* common fields in the packet header */
size_t rem; size_t rem;
size_t idx; size_t idx;
int8_t he = HEADER_ENCRYPTION_UNKNOWN;
size_t msg_type; size_t msg_type;
uint8_t from_supernode; uint8_t from_supernode;
macstr_t mac_buf; macstr_t mac_buf;
macstr_t mac_buf2; macstr_t mac_buf2;
n2n_sock_str_t sockbuf; n2n_sock_str_t sockbuf;
char buf[32]; char buf[32];
struct sn_community *comm, *tmp;
traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]", 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)), udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)),
ntohs(sender_sock->sin_port)); ntohs(sender_sock->sin_port));
he = packet_header_decrypt_if_required (udp_buf, udp_size, sss->communities); /* check if header is unenrypted. the following check is around 99.99962 percent reliable.
if (he < 0) * it heavily relies on the structure of packet's common part
return -1; /* something wrong during packet decryption */ * 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: /* Use decode_common() to determine the kind of packet then process it:
* *
@ -409,8 +447,7 @@ static int process_udp(n2n_sn_t *sss,
rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */ rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */
idx = 0; /* marches through packet header as parts are decoded. */ idx = 0; /* marches through packet header as parts are decoded. */
if (decode_common(&cmn, udp_buf, &rem, &idx) < 0) if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) {
{
traceEvent(TRACE_ERROR, "Failed to decode common section"); traceEvent(TRACE_ERROR, "Failed to decode common section");
return -1; /* failed to decode packet */ return -1; /* failed to decode packet */
} }
@ -418,16 +455,14 @@ static int process_udp(n2n_sn_t *sss,
msg_type = cmn.pc; /* packet code */ msg_type = cmn.pc; /* packet code */
from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE; from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
if (cmn.ttl < 1) if(cmn.ttl < 1) {
{
traceEvent(TRACE_WARNING, "Expired TTL"); traceEvent(TRACE_WARNING, "Expired TTL");
return 0; /* Don't process further */ return 0; /* Don't process further */
} }
--(cmn.ttl); /* The value copied into all forwarded packets. */ --(cmn.ttl); /* The value copied into all forwarded packets. */
switch (msg_type) switch(msg_type) {
{
case MSG_TYPE_PACKET: case MSG_TYPE_PACKET:
{ {
/* PACKET from one edge to another edge via supernode. */ /* PACKET from one edge to another edge via supernode. */
@ -439,7 +474,12 @@ static int process_udp(n2n_sn_t *sss,
uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
int unicast; /* non-zero if unicast */ 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; sss->stats.last_fwd=now;
decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx);
@ -452,8 +492,7 @@ static int process_udp(n2n_sn_t *sss,
macaddr_str(mac_buf2, pkt.dstMac), macaddr_str(mac_buf2, pkt.dstMac),
(from_supernode?"from sn":"local")); (from_supernode?"from sn":"local"));
if (!from_supernode) if(!from_supernode) {
{
memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
/* We are going to add socket even if it was not there before */ /* We are going to add socket even if it was not there before */
@ -468,11 +507,12 @@ static int process_udp(n2n_sn_t *sss,
/* Re-encode the header. */ /* Re-encode the header. */
encode_PACKET(encbuf, &encx, &cmn2, &pkt); 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 */ /* Copy the original payload unchanged */
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx)); encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
} } else {
else
{
/* Already from a supernode. Nothing to modify, just pass to /* Already from a supernode. Nothing to modify, just pass to
* destination. */ * destination. */
@ -480,13 +520,16 @@ static int process_udp(n2n_sn_t *sss,
rec_buf = udp_buf; rec_buf = udp_buf;
encx = udp_size; 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. */ /* Common section to forward the final product. */
if(unicast) if(unicast)
try_forward(sss, &cmn, pkt.dstMac, rec_buf, encx); try_forward(sss, comm, &cmn, pkt.dstMac, rec_buf, encx);
else else
try_broadcast(sss, &cmn, pkt.srcMac, rec_buf, encx); try_broadcast(sss, comm, &cmn, pkt.srcMac, rec_buf, encx);
break; break;
} }
case MSG_TYPE_REGISTER: case MSG_TYPE_REGISTER:
@ -498,22 +541,25 @@ static int process_udp(n2n_sn_t *sss,
uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
int unicast; /* non-zero if unicast */ 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; sss->stats.last_fwd=now;
decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx);
unicast = (0 == is_multi_broadcast(reg.dstMac)); unicast = (0 == is_multi_broadcast(reg.dstMac));
if (unicast) if(unicast) {
{
traceEvent(TRACE_DEBUG, "Rx REGISTER %s -> %s %s", traceEvent(TRACE_DEBUG, "Rx REGISTER %s -> %s %s",
macaddr_str(mac_buf, reg.srcMac), macaddr_str(mac_buf, reg.srcMac),
macaddr_str(mac_buf2, reg.dstMac), macaddr_str(mac_buf2, reg.dstMac),
((cmn.flags & N2N_FLAGS_FROM_SUPERNODE)?"from sn":"local")); ((cmn.flags & N2N_FLAGS_FROM_SUPERNODE)?"from sn":"local"));
if (0 == (cmn.flags & N2N_FLAGS_FROM_SUPERNODE)) if(0 == (cmn.flags & N2N_FLAGS_FROM_SUPERNODE)) {
{
memcpy(&cmn2, &cmn, sizeof(n2n_common_t)); memcpy(&cmn2, &cmn, sizeof(n2n_common_t));
/* We are going to add socket even if it was not there before */ /* We are going to add socket even if it was not there before */
@ -530,9 +576,7 @@ static int process_udp(n2n_sn_t *sss,
/* Copy the original payload unchanged */ /* Copy the original payload unchanged */
encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx)); encode_buf(encbuf, &encx, (udp_buf + idx), (udp_size - idx));
} } else {
else
{
/* Already from a supernode. Nothing to modify, just pass to /* Already from a supernode. Nothing to modify, just pass to
* destination. */ * destination. */
@ -540,9 +584,11 @@ static int process_udp(n2n_sn_t *sss,
encx = udp_size; 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);
else
try_forward(sss, comm, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */
} else
traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination"); traceEvent(TRACE_ERROR, "Rx REGISTER with multicast destination");
break; break;
} }
@ -556,27 +602,22 @@ static int process_udp(n2n_sn_t *sss,
n2n_common_t cmn2; n2n_common_t cmn2;
uint8_t ackbuf[N2N_SN_PKTBUF_SIZE]; uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
struct sn_community *comm;
/* Edge requesting registration with us. */ /* Edge requesting registration with us. */
sss->stats.last_reg_super=now; sss->stats.last_reg_super=now;
++(sss->stats.reg_super); ++(sss->stats.reg_super);
decode_REGISTER_SUPER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER_SUPER(&reg, &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 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 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 not report any message back to the edge to hide the supernode
existance (better from the security standpoint) existance (better from the security standpoint)
*/ */
if (!comm && !sss->lock_communities) if(!comm && !sss->lock_communities) {
{
comm = calloc(1, sizeof(struct sn_community)); comm = calloc(1, sizeof(struct sn_community));
if (comm) if(comm) {
{
strncpy(comm->community, (char*)cmn.community, N2N_COMMUNITY_SIZE-1); strncpy(comm->community, (char*)cmn.community, N2N_COMMUNITY_SIZE-1);
comm->community[N2N_COMMUNITY_SIZE-1] = '\0'; comm->community[N2N_COMMUNITY_SIZE-1] = '\0';
/* new communities introduced by REGISTERs could not have had encrypted header */ /* new communities introduced by REGISTERs could not have had encrypted header */
@ -589,8 +630,7 @@ static int process_udp(n2n_sn_t *sss,
} }
} }
if (comm) if(comm) {
{
cmn2.ttl = N2N_DEFAULT_TTL; cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_register_super_ack; cmn2.pc = n2n_register_super_ack;
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
@ -615,26 +655,31 @@ static int process_udp(n2n_sn_t *sss,
encode_REGISTER_SUPER_ACK(ackbuf, &encx, &cmn2, &ack); 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, sendto(sss->sock, ackbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in));
traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]", traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]",
macaddr_str(mac_buf, reg.edgeMac), macaddr_str(mac_buf, reg.edgeMac),
sock_to_cstr(sockbuf, &(ack.sock))); sock_to_cstr(sockbuf, &(ack.sock)));
} } else
else
traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'", traceEvent(TRACE_INFO, "Discarded registration: unallowed community '%s'",
(char*)cmn.community); (char*)cmn.community);
break; break;
} }
case MSG_TYPE_QUERY_PEER: case MSG_TYPE_QUERY_PEER: {
{
n2n_QUERY_PEER_t query; n2n_QUERY_PEER_t query;
uint8_t encbuf[N2N_SN_PKTBUF_SIZE]; uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
size_t encx=0; size_t encx=0;
n2n_common_t cmn2; n2n_common_t cmn2;
n2n_PEER_INFO_t pi; 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 ); decode_QUERY_PEER( &query, &cmn, udp_buf, &rem, &idx );
@ -642,15 +687,10 @@ static int process_udp(n2n_sn_t *sss,
macaddr_str( mac_buf, query.srcMac ), macaddr_str( mac_buf, query.srcMac ),
macaddr_str( mac_buf2, query.targetMac ) ); macaddr_str( mac_buf2, query.targetMac ) );
HASH_FIND_COMMUNITY(sss->communities, (char *)cmn.community, community);
if (community)
{
struct peer_info *scan; struct peer_info *scan;
HASH_FIND_PEER(community->edges, query.targetMac, scan); HASH_FIND_PEER(comm->edges, query.targetMac, scan);
if (scan) if (scan) {
{
cmn2.ttl = N2N_DEFAULT_TTL; cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_peer_info; cmn2.pc = n2n_peer_info;
cmn2.flags = N2N_FLAGS_FROM_SUPERNODE; cmn2.flags = N2N_FLAGS_FROM_SUPERNODE;
@ -662,18 +702,18 @@ static int process_udp(n2n_sn_t *sss,
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, sendto( sss->sock, encbuf, encx, 0,
(struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) ); (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s", traceEvent( TRACE_DEBUG, "Tx PEER_INFO to %s",
macaddr_str( mac_buf, query.srcMac ) ); macaddr_str( mac_buf, query.srcMac ) );
} } else {
else
{
traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s", traceEvent( TRACE_DEBUG, "Ignoring QUERY_PEER for unknown edge %s",
macaddr_str( mac_buf, query.targetMac ) ); macaddr_str( mac_buf, query.targetMac ) );
} }
}
break; break;
} }

Loading…
Cancel
Save