Browse Source

Initial code rework (wip)

- The edge structure is now opaque
- The configuration is now exposed via an API
- Code cleanup: using multiple transops at once is not supported anymore
pull/100/head
emanuele-f 6 years ago
parent
commit
e757f94efa
  1. 192
      edge.c
  2. 438
      edge_utils.c
  3. 76
      n2n.h
  4. 52
      n2n_transforms.h

192
edge.c

@ -35,22 +35,20 @@
/* ***************************************************** */ /* ***************************************************** */
typedef struct { typedef struct n2n_priv_config {
int local_port;
int mgmt_port;
char tuntap_dev_name[N2N_IFNAMSIZ]; char tuntap_dev_name[N2N_IFNAMSIZ];
char ip_mode[N2N_IF_MODE_SIZE]; char ip_mode[N2N_IF_MODE_SIZE];
char ip_addr[N2N_NETMASK_STR_SIZE]; char ip_addr[N2N_NETMASK_STR_SIZE];
char netmask[N2N_NETMASK_STR_SIZE]; char netmask[N2N_NETMASK_STR_SIZE];
int mtu;
int got_s;
char device_mac[N2N_MACNAMSIZ]; char device_mac[N2N_MACNAMSIZ];
char * encrypt_key; int mtu;
uint8_t got_s;
uint8_t daemon;
#ifndef WIN32 #ifndef WIN32
uid_t userid; uid_t userid;
gid_t groupid; gid_t groupid;
#endif #endif
} edge_conf_t; } n2n_priv_config_t;
/* ***************************************************** */ /* ***************************************************** */
@ -177,21 +175,21 @@ static void help() {
/* *************************************************** */ /* *************************************************** */
static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t *eee) { static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_edge_conf_t *conf) {
/* traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, optargument ? optargument : ""); */ /* traceEvent(TRACE_NORMAL, "Option %c = %s", optkey, optargument ? optargument : ""); */
switch(optkey) { switch(optkey) {
case'K': case'K':
{ {
if(ec->encrypt_key) { if(conf->encrypt_key) {
traceEvent(TRACE_ERROR, "Error: -K and -k options are mutually exclusive"); traceEvent(TRACE_ERROR, "Error: -K and -k options are mutually exclusive");
exit(1); exit(1);
} else { } else {
strncpy(eee->keyschedule, optargument, N2N_PATHNAME_MAXLEN-1); strncpy(conf->keyschedule, optargument, N2N_PATHNAME_MAXLEN-1);
/* strncpy does not add NULL if the source has no NULL. */ /* strncpy does not add NULL if the source has no NULL. */
eee->keyschedule[N2N_PATHNAME_MAXLEN-1] = 0; conf->keyschedule[N2N_PATHNAME_MAXLEN-1] = 0;
traceEvent(TRACE_NORMAL, "keyfile = '%s'\n", eee->keyschedule); traceEvent(TRACE_NORMAL, "keyfile = '%s'\n", conf->keyschedule);
} }
break; break;
} }
@ -206,14 +204,14 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
case 'c': /* community as a string */ case 'c': /* community as a string */
{ {
memset(eee->community_name, 0, N2N_COMMUNITY_SIZE); memset(conf->community_name, 0, N2N_COMMUNITY_SIZE);
strncpy((char *)eee->community_name, optargument, N2N_COMMUNITY_SIZE); strncpy((char *)conf->community_name, optargument, N2N_COMMUNITY_SIZE);
break; break;
} }
case 'E': /* multicast ethernet addresses accepted. */ case 'E': /* multicast ethernet addresses accepted. */
{ {
eee->drop_multicast=0; conf->drop_multicast=0;
traceEvent(TRACE_DEBUG, "Enabling ethernet multicast traffic"); traceEvent(TRACE_DEBUG, "Enabling ethernet multicast traffic");
break; break;
} }
@ -235,7 +233,7 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
#ifndef WIN32 #ifndef WIN32
case 'f' : /* do not fork as daemon */ case 'f' : /* do not fork as daemon */
{ {
eee->daemon=0; ec->daemon=0;
break; break;
} }
#endif /* #ifndef WIN32 */ #endif /* #ifndef WIN32 */
@ -254,37 +252,34 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
case 'k': /* encrypt key */ case 'k': /* encrypt key */
{ {
if(strlen(eee->keyschedule) > 0) { if(strlen(conf->keyschedule) > 0) {
traceEvent(TRACE_ERROR, "-K and -k options are mutually exclusive"); traceEvent(TRACE_ERROR, "-K and -k options are mutually exclusive");
exit(1); exit(1);
} else { } else {
traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", ec->encrypt_key); if(conf->encrypt_key) free(conf->encrypt_key);
ec->encrypt_key = strdup(optargument); conf->encrypt_key = strdup(optargument);
traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", conf->encrypt_key);
} }
break; break;
} }
case 'r': /* enable packet routing across n2n endpoints */ case 'r': /* enable packet routing across n2n endpoints */
{ {
eee->allow_routing = 1; conf->allow_routing = 1;
break; break;
} }
#ifdef N2N_HAVE_AES #ifdef N2N_HAVE_AES
case 'A': case 'A':
{ {
eee->preferred_aes = 1; conf->transop_id = N2N_TRANSFORM_ID_AESCBC;
break; break;
} }
#endif #endif
case 'l': /* supernode-list */ case 'l': /* supernode-list */
if(optargument) { if(optargument) {
if(eee->sn_num < N2N_EDGE_NUM_SUPERNODES) { if(edge_conf_add_supernode(conf, optargument) != 0) {
strncpy((eee->sn_ip_array[eee->sn_num]), optargument, N2N_EDGE_SN_HOST_SIZE);
traceEvent(TRACE_NORMAL, "Adding supernode[%u] = %s", (unsigned int)eee->sn_num, (eee->sn_ip_array[eee->sn_num]));
++eee->sn_num;
} else {
traceEvent(TRACE_WARNING, "Too many supernodes!"); traceEvent(TRACE_WARNING, "Too many supernodes!");
exit(1); exit(1);
} }
@ -301,19 +296,19 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t
case 'b': case 'b':
{ {
eee->re_resolve_supernode_ip = 1; conf->re_resolve_supernode_ip = 1;
break; break;
} }
case 'p': case 'p':
{ {
ec->local_port = atoi(optargument); conf->local_port = atoi(optargument);
break; break;
} }
case 't': case 't':
{ {
ec->mgmt_port = atoi(optargument); conf->mgmt_port = atoi(optargument);
break; break;
} }
@ -363,7 +358,7 @@ static const struct option long_options[] = {
/* *************************************************** */ /* *************************************************** */
/* read command line options */ /* read command line options */
static int loadFromCLI(int argc, char *argv[], edge_conf_t *ec, n2n_edge_t *eee) { static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_priv_config_t *ec) {
u_char c; u_char c;
while((c = getopt_long(argc, argv, while((c = getopt_long(argc, argv,
@ -374,7 +369,7 @@ static int loadFromCLI(int argc, char *argv[], edge_conf_t *ec, n2n_edge_t *eee)
, ,
long_options, NULL)) != '?') { long_options, NULL)) != '?') {
if(c == 255) break; if(c == 255) break;
setOption(c, optarg, ec, eee); setOption(c, optarg, ec, conf);
} }
return 0; return 0;
@ -400,7 +395,7 @@ static char *trim(char *s) {
/* *************************************************** */ /* *************************************************** */
/* parse the configuration file */ /* parse the configuration file */
static int loadFromFile(const char *path, edge_conf_t *ec, n2n_edge_t *eee) { static int loadFromFile(const char *path, n2n_edge_conf_t *conf, n2n_priv_config_t *ec) {
char buffer[4096], *line, *key, *value; char buffer[4096], *line, *key, *value;
u_int line_len, opt_name_len; u_int line_len, opt_name_len;
FILE *fd; FILE *fd;
@ -414,7 +409,6 @@ static int loadFromFile(const char *path, edge_conf_t *ec, n2n_edge_t *eee) {
} }
while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) {
line = trim(line); line = trim(line);
value = NULL; value = NULL;
@ -437,7 +431,7 @@ static int loadFromFile(const char *path, edge_conf_t *ec, n2n_edge_t *eee) {
if(line_len > opt_name_len + 1) value = trim(&key[opt_name_len + 1]); if(line_len > opt_name_len + 1) value = trim(&key[opt_name_len + 1]);
// traceEvent(TRACE_NORMAL, "long key: %s value: %s", key, value); // traceEvent(TRACE_NORMAL, "long key: %s value: %s", key, value);
setOption(opt->val, value, ec, eee); setOption(opt->val, value, ec, conf);
break; break;
} }
@ -449,7 +443,7 @@ static int loadFromFile(const char *path, edge_conf_t *ec, n2n_edge_t *eee) {
if(line_len > 2) value = trim(&key[2]); if(line_len > 2) value = trim(&key[2]);
// traceEvent(TRACE_NORMAL, "key: %c value: %s", key[0], value); // traceEvent(TRACE_NORMAL, "key: %c value: %s", key[0], value);
setOption(key[0], value, ec, eee); setOption(key[0], value, ec, conf);
} else { } else {
traceEvent(TRACE_WARNING, "Skipping unrecognized line: %s", line); traceEvent(TRACE_WARNING, "Skipping unrecognized line: %s", line);
continue; continue;
@ -563,89 +557,87 @@ static void daemonize() {
/* *************************************************** */ /* *************************************************** */
void edge_conf_init_defaults(n2n_edge_conf_t *conf) {
memset(conf, 0, sizeof(*conf));
conf->local_port = 0 /* any port */;
conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
conf->transop_id = N2N_TRANSFORM_ID_TWOFISH; /* use twofish for compatibility */
conf->drop_multicast = 1;
if(getenv("N2N_KEY"))
conf->encrypt_key = strdup(getenv("N2N_KEY"));
}
/* *************************************************** */
/** Entry point to program from kernel. */ /** Entry point to program from kernel. */
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
int keep_on_running = 1; int keep_on_running = 1;
int rc; int rc;
int i; tuntap_dev tuntap; /* a tuntap device */
n2n_edge_t eee; /* single instance for this program */ n2n_edge_t *eee; /* single instance for this program */
edge_conf_t ec; n2n_edge_conf_t conf; /* generic N2N edge config */
n2n_priv_config_t ec; /* config used for standalone program execution */
if(argc == 1) if(argc == 1)
help(); help();
ec.local_port = 0 /* any port */; /* Defaults */
ec.mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */ edge_conf_init_defaults(&conf);
snprintf(ec.tuntap_dev_name, sizeof(ec.tuntap_dev_name), "edge0");
snprintf(ec.ip_mode, sizeof(ec.ip_mode), "static");
snprintf(ec.netmask, sizeof(ec.netmask), "255.255.255.0");
ec.ip_addr[0] = '\0';
ec.device_mac[0] = '\0';
ec.mtu = DEFAULT_MTU; ec.mtu = DEFAULT_MTU;
ec.got_s = 0; ec.daemon = 1; /* By default run in daemon mode. */
ec.encrypt_key = NULL;
#ifndef WIN32 #ifndef WIN32
ec.userid = 0; /* root is the only guaranteed ID */ ec.userid = 0; /* root is the only guaranteed ID */
ec.groupid = 0; /* root is the only guaranteed ID */ ec.groupid = 0; /* root is the only guaranteed ID */
#endif #endif
if(-1 == edge_init(&eee)) {
traceEvent(TRACE_ERROR, "Failed in edge_init");
exit(1);
}
if(getenv("N2N_KEY")) {
ec.encrypt_key = strdup(getenv("N2N_KEY"));
}
#ifdef WIN32 #ifdef WIN32
ec.tuntap_dev_name[0] = '\0'; ec.tuntap_dev_name[0] = '\0';
#else
snprintf(ec.tuntap_dev_name, sizeof(ec.tuntap_dev_name), "edge0");
#endif #endif
memset(&(eee.supernode), 0, sizeof(eee.supernode)); snprintf(ec.ip_mode, sizeof(ec.ip_mode), "static");
eee.supernode.family = AF_INET; snprintf(ec.netmask, sizeof(ec.netmask), "255.255.255.0");
#ifndef WIN32 #ifndef WIN32
if((argc >= 2) && (argv[1][0] != '-')) { if((argc >= 2) && (argv[1][0] != '-')) {
rc = loadFromFile(argv[1], &ec, &eee); rc = loadFromFile(argv[1], &conf, &ec);
if(argc > 2) if(argc > 2)
rc = loadFromCLI(argc, argv, &ec, &eee); rc = loadFromCLI(argc, argv, &conf, &ec);
} else } else
#endif #endif
rc = loadFromCLI(argc, argv, &ec, &eee); rc = loadFromCLI(argc, argv, &conf, &ec);
if((rc < 0) || (eee.sn_num == 0)) if(rc < 0)
help(); help();
traceEvent(TRACE_NORMAL, "Starting n2n edge %s %s", PACKAGE_VERSION, PACKAGE_BUILDDATE); traceEvent(TRACE_NORMAL, "Starting n2n edge %s %s", PACKAGE_VERSION, PACKAGE_BUILDDATE);
for (i=0; i<eee.sn_num; ++i) if(0 == strcmp("dhcp", ec.ip_mode)) {
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (eee.sn_ip_array[i])); traceEvent(TRACE_NORMAL, "Dynamic IP address assignment enabled.");
conf.dyn_ip_mode = 1;
} else
traceEvent(TRACE_NORMAL, "ip_mode='%s'", ec.ip_mode);
supernode2addr(&(eee.supernode), eee.sn_ip_array[eee.sn_idx]); if(edge_verify_conf(&conf) != 0)
help();
if(!( if(!(
#ifdef __linux__ #ifdef __linux__
(ec.tuntap_dev_name[0] != 0) && (ec.tuntap_dev_name[0] != 0) &&
#endif #endif
(eee.community_name[0] != 0) &&
(ec.ip_addr[0] != 0) (ec.ip_addr[0] != 0)
)) ))
{
help(); help();
}
#ifndef WIN32 if(tuntap_open(&tuntap, ec.tuntap_dev_name, ec.ip_mode, ec.ip_addr, ec.netmask, ec.device_mac, ec.mtu) < 0)
if(eee.daemon) { return(-1);
setUseSyslog(1); /* traceEvent output now goes to syslog. */
daemonize();
}
#endif /* #ifndef WIN32 */
if((NULL == ec.encrypt_key) && (0 == strlen(eee.keyschedule)))
{
traceEvent(TRACE_WARNING, "Encryption is disabled in edge.");
eee.null_transop = 1; if((eee = edge_init(&tuntap, &conf, &rc)) == NULL) {
traceEvent(TRACE_ERROR, "Failed in edge_init");
exit(1);
} }
#ifndef WIN32 #ifndef WIN32
@ -654,15 +646,12 @@ int main(int argc, char* argv[]) {
/* setgid(0); */ /* setgid(0); */
#endif #endif
if(0 == strcmp("dhcp", ec.ip_mode)) { #ifndef WIN32
traceEvent(TRACE_NORMAL, "Dynamic IP address assignment enabled."); if(ec.daemon) {
setUseSyslog(1); /* traceEvent output now goes to syslog. */
eee.dyn_ip_mode = 1; daemonize();
} else }
traceEvent(TRACE_NORMAL, "ip_mode='%s'", ec.ip_mode); #endif /* #ifndef WIN32 */
if(tuntap_open(&(eee.device), ec.tuntap_dev_name, ec.ip_mode, ec.ip_addr, ec.netmask, ec.device_mac, ec.mtu) < 0)
return(-1);
#ifndef WIN32 #ifndef WIN32
if((ec.userid != 0) || (ec.groupid != 0)) { if((ec.userid != 0) || (ec.groupid != 0)) {
@ -675,30 +664,13 @@ int main(int argc, char* argv[]) {
} }
#endif #endif
if(ec.local_port > 0)
traceEvent(TRACE_NORMAL, "Binding to local port %d", (signed int)ec.local_port);
if(ec.encrypt_key) {
if(edge_init_encryption(&eee, (uint8_t *)ec.encrypt_key, strlen(ec.encrypt_key)) != 0) {
traceEvent(TRACE_ERROR, "Error: encryption setup failed");
return(-1);
}
} else if(strlen(eee.keyschedule) > 0) {
if(edge_init_keyschedule(&eee) < 0) {
traceEvent(TRACE_ERROR, "Error: keyschedule setup failed");
return(-1);
}
}
/* else run in NULL mode */
if(edge_init_sockets(&eee, ec.local_port, ec.mgmt_port) < 0) {
traceEvent(TRACE_ERROR, "Error: socket setup failed");
return(-1);
}
traceEvent(TRACE_NORMAL, "edge started"); traceEvent(TRACE_NORMAL, "edge started");
return run_edge_loop(&eee, &keep_on_running); rc = run_edge_loop(eee, &keep_on_running);
edge_term(eee);
tuntap_close(&tuntap);
return(rc);
} }
/* ************************************** */ /* ************************************** */

438
edge_utils.c

@ -46,15 +46,6 @@
#define ARP_PERIOD_INTERVAL (10) /* sec */ #define ARP_PERIOD_INTERVAL (10) /* sec */
#endif #endif
/** Positions in the transop array where various transforms are stored.
*
* Used by transop_enum_to_index(). See also the transform enumerations in
* n2n_transforms.h */
#define N2N_TRANSOP_NULL_IDX 0
#define N2N_TRANSOP_TF_IDX 1
#define N2N_TRANSOP_AESCBC_IDX 2
/* etc. */
#define ETH_FRAMESIZE 14 #define ETH_FRAMESIZE 14
#define IP4_SRCOFFSET 12 #define IP4_SRCOFFSET 12
#define IP4_DSTOFFSET 16 #define IP4_DSTOFFSET 16
@ -67,6 +58,58 @@ static void check_peer(n2n_edge_t * eee,
uint8_t from_supernode, uint8_t from_supernode,
const n2n_mac_t mac, const n2n_mac_t mac,
const n2n_sock_t * peer); const n2n_sock_t * peer);
static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port);
static int edge_init_keyschedule(n2n_edge_t * eee);
/* ************************************** */
int edge_verify_conf(const n2n_edge_conf_t *conf) {
if(conf->community_name[0] == 0)
return(-1);
if(conf->sn_num == 0)
return(-2);
return(0);
}
/* ************************************** */
struct n2n_edge {
n2n_edge_conf_t conf;
/* Status */
uint8_t sn_idx; /**< Currently active supernode. */
uint8_t sn_wait; /**< Whether we are waiting for a supernode response. */
size_t sup_attempts; /**< Number of remaining attempts to this supernode. */
tuntap_dev device; /**< All about the TUNTAP device */
n2n_trans_op_t transop; /**< The transop to use when encoding */
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
/* Sockets */
n2n_sock_t supernode;
n2n_sock_t multicast_peer; /**< Multicast peer group (for local edges) */
int udp_sock;
int udp_mgmt_sock; /**< socket for status info. */
int udp_multicast_sock; /**< socket for local multicast registrations. */
/* Peers */
struct peer_info * known_peers; /**< Edges we are connected to. */
struct peer_info * pending_peers; /**< Edges we have tried to register with. */
/* Timers */
time_t last_register_req; /**< Check if time to re-register with super*/
size_t register_lifetime; /**< Time distance after last_register_req at which to re-register. */
time_t last_p2p; /**< Last time p2p traffic was received. */
time_t last_sup; /**< Last time a packet arrived from supernode. */
time_t start_time; /**< For calculating uptime */
/* Statistics */
size_t tx_p2p;
size_t rx_p2p;
size_t tx_sup;
size_t rx_sup;
};
/* ************************************** */ /* ************************************** */
@ -74,49 +117,89 @@ static void check_peer(n2n_edge_t * eee,
* *
* This also initialises the NULL transform operation opstruct. * This also initialises the NULL transform operation opstruct.
*/ */
int edge_init(n2n_edge_t * eee) { n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv) {
n2n_transform_id_t transop_id = conf->transop_id;
n2n_edge_t *eee = calloc(1, sizeof(n2n_edge_t));
int rc = -1;
if((rc = edge_verify_conf(conf)) != 0) {
traceEvent(TRACE_ERROR, "Invalid configuration");
goto edge_init_error;
}
if(!eee) {
traceEvent(TRACE_ERROR, "Cannot allocate memory");
goto edge_init_error;
}
#ifdef WIN32 #ifdef WIN32
initWin32(); initWin32();
#endif #endif
memset(eee, 0, sizeof(n2n_edge_t)); memcpy(&eee->conf, conf, sizeof(*conf));
memcpy(&eee->device, dev, sizeof(*dev));
eee->start_time = time(NULL); eee->start_time = time(NULL);
/* REVISIT: BbMaj7 : Should choose something with less predictability /* REVISIT: BbMaj7 : Should choose something with less predictability
* particularly for embedded targets with no real-time clock. */ * particularly for embedded targets with no real-time clock. */
srand(eee->start_time); srand(eee->start_time);
transop_null_init( &(eee->transop[N2N_TRANSOP_NULL_IDX]));
transop_twofish_init(&(eee->transop[N2N_TRANSOP_TF_IDX] ));
transop_aes_init(&(eee->transop[N2N_TRANSOP_AESCBC_IDX] ));
eee->tx_transop_idx = N2N_TRANSOP_NULL_IDX; /* No guarantee the others have been setup */
eee->daemon = 1; /* By default run in daemon mode. */
eee->preferred_aes = 0; /* Disable AES by default (for compatibility) */
eee->re_resolve_supernode_ip = 0;
/* keyschedule set to NULLs by memset */
/* community_name set to NULLs by memset */
eee->null_transop = 0;
eee->udp_sock = -1;
eee->udp_mgmt_sock = -1;
eee->udp_multicast_sock = -1;
eee->dyn_ip_mode = 0;
eee->allow_routing = 0;
eee->drop_multicast = 1;
eee->known_peers = NULL; eee->known_peers = NULL;
eee->pending_peers = NULL; eee->pending_peers = NULL;
eee->last_register_req = 0;
eee->register_lifetime = REGISTER_SUPER_INTERVAL_DFL; eee->register_lifetime = REGISTER_SUPER_INTERVAL_DFL;
eee->last_p2p = 0;
eee->last_sup = 0;
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
#ifdef NOT_USED
if(lzo_init() != LZO_E_OK) { if(lzo_init() != LZO_E_OK) {
traceEvent(TRACE_ERROR, "LZO compression error"); traceEvent(TRACE_ERROR, "LZO compression error");
return(-1); goto edge_init_error;
} }
#endif
return(0); for(int i=0; i<conf->sn_num; ++i)
traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (conf->sn_ip_array[i]));
/* Set the active supernode */
supernode2addr(&(eee->supernode), conf->sn_ip_array[eee->sn_idx]);
/* Set active transop */
if((conf->encrypt_key == NULL) && (strlen(eee->conf.keyschedule) == 0))
transop_id = N2N_TRANSFORM_ID_NULL;
switch(transop_id) {
case N2N_TRANSFORM_ID_TWOFISH:
rc = n2n_transop_twofish_init(eee, &eee->transop);
break;
#ifdef N2N_HAVE_AES
case N2N_TRANSFORM_ID_AESCBC:
rc = n2n_transop_aes_init(eee, &eee->transop);
break;
#endif
default:
rc = n2n_transop_null_init(eee, &eee->transop);
}
if((rc < 0) || (eee->transop.fwd == NULL) || (eee->transop.transform_id != transop_id)) {
traceEvent(TRACE_ERROR, "Transop init failed");
goto edge_init_error;
}
if(eee->transop.no_encryption)
traceEvent(TRACE_WARNING, "Encryption is disabled in edge");
if(edge_init_sockets(eee, conf->local_port, conf->mgmt_port) < 0) {
traceEvent(TRACE_ERROR, "Error: socket setup failed");
goto edge_init_error;
}
//edge_init_success:
*rv = 0;
return(eee);
edge_init_error:
if(eee)
free(eee);
*rv = rc;
return(NULL);
} }
/* ***************************************************** */ /* ***************************************************** */
@ -501,7 +584,7 @@ static void send_register_super(n2n_edge_t * eee,
cmn.ttl=N2N_DEFAULT_TTL; cmn.ttl=N2N_DEFAULT_TTL;
cmn.pc = n2n_register_super; cmn.pc = n2n_register_super;
cmn.flags = 0; cmn.flags = 0;
memcpy(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE); memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
for(idx=0; idx < N2N_COOKIE_SIZE; ++idx) for(idx=0; idx < N2N_COOKIE_SIZE; ++idx)
eee->last_cookie[idx] = rand() % 0xff; eee->last_cookie[idx] = rand() % 0xff;
@ -538,7 +621,7 @@ static void send_register(n2n_edge_t * eee,
cmn.ttl=N2N_DEFAULT_TTL; cmn.ttl=N2N_DEFAULT_TTL;
cmn.pc = n2n_register; cmn.pc = n2n_register;
cmn.flags = 0; cmn.flags = 0;
memcpy(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE); memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
idx=0; idx=0;
encode_uint32(reg.cookie, &idx, 123456789); encode_uint32(reg.cookie, &idx, 123456789);
@ -572,7 +655,7 @@ static void send_register_ack(n2n_edge_t * eee,
cmn.ttl=N2N_DEFAULT_TTL; cmn.ttl=N2N_DEFAULT_TTL;
cmn.pc = n2n_register_ack; cmn.pc = n2n_register_ack;
cmn.flags = 0; cmn.flags = 0;
memcpy(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE); memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
memset(&ack, 0, sizeof(ack)); memset(&ack, 0, sizeof(ack));
memcpy(ack.cookie, reg->cookie, N2N_COOKIE_SIZE); memcpy(ack.cookie, reg->cookie, N2N_COOKIE_SIZE);
@ -608,24 +691,24 @@ static void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) {
/* Give up on that supernode and try the next one. */ /* Give up on that supernode and try the next one. */
++(eee->sn_idx); ++(eee->sn_idx);
if (eee->sn_idx >= eee->sn_num) { if (eee->sn_idx >= eee->conf.sn_num) {
/* Got to end of list, go back to the start. Also works for list of one entry. */ /* Got to end of list, go back to the start. Also works for list of one entry. */
eee->sn_idx=0; eee->sn_idx=0;
} }
traceEvent(TRACE_WARNING, "Supernode not responding - moving to %u of %u", traceEvent(TRACE_WARNING, "Supernode not responding - moving to %u of %u",
(unsigned int)eee->sn_idx, (unsigned int)eee->sn_num); (unsigned int)eee->sn_idx, (unsigned int)eee->conf.sn_num);
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
} }
else else
--(eee->sup_attempts); --(eee->sup_attempts);
for(sn_idx=0; sn_idx<eee->sn_num; sn_idx++) { for(sn_idx=0; sn_idx<eee->conf.sn_num; sn_idx++) {
supernode2addr(&(eee->supernode), eee->sn_ip_array[sn_idx]); supernode2addr(&(eee->supernode), eee->conf.sn_ip_array[sn_idx]);
traceEvent(TRACE_INFO, "Registering with supernode [id: %u/%u][%s][attempts left %u]", traceEvent(TRACE_INFO, "Registering with supernode [id: %u/%u][%s][attempts left %u]",
sn_idx+1, eee->sn_num, sn_idx+1, eee->conf.sn_num,
supernode_ip(eee), (unsigned int)eee->sup_attempts); supernode_ip(eee), (unsigned int)eee->sup_attempts);
send_register_super(eee, &(eee->supernode)); send_register_super(eee, &(eee->supernode));
@ -657,93 +740,19 @@ static void send_deregister(n2n_edge_t * eee,
/** Return the IP address of the current supernode in the ring. */ /** Return the IP address of the current supernode in the ring. */
static const char * supernode_ip(const n2n_edge_t * eee) { static const char * supernode_ip(const n2n_edge_t * eee) {
return (eee->sn_ip_array)[eee->sn_idx]; return (eee->conf.sn_ip_array)[eee->sn_idx];
}
/* ************************************** */
static int edge_init_twofish_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
uint32_t encrypt_pwd_len) {
return transop_twofish_setup_psk(&(eee->transop[N2N_TRANSOP_TF_IDX]),
0, encrypt_pwd, encrypt_pwd_len);
}
/* ************************************** */
static int edge_init_aes_psk(n2n_edge_t * eee, uint8_t *encrypt_pwd,
uint32_t encrypt_pwd_len) {
return transop_aes_setup_psk(&(eee->transop[N2N_TRANSOP_AESCBC_IDX]),
0, encrypt_pwd, encrypt_pwd_len);
}
/* ************************************** */
int edge_init_encryption(n2n_edge_t * eee, uint8_t *encrypt_pwd, uint32_t encrypt_pwd_len) {
#ifdef N2N_HAVE_AES
if(edge_init_aes_psk(eee, encrypt_pwd, encrypt_pwd_len) < 0) {
traceEvent(TRACE_ERROR, "Error: AES PSK setup failed");
return(-1);
}
#endif
if(edge_init_twofish_psk(eee, encrypt_pwd, encrypt_pwd_len) < 0) {
traceEvent(TRACE_ERROR, "Error: twofish PSK setup failed");
return(-1);
}
return(0);
}
/* ************************************** */
static n2n_tostat_t n2n_tick_aes(n2n_edge_t * eee, time_t now, size_t *trop) {
n2n_tostat_t tst = (eee->transop[N2N_TRANSOP_AESCBC_IDX].tick)(&(eee->transop[N2N_TRANSOP_AESCBC_IDX]), now);
if(tst.can_tx)
{
traceEvent(TRACE_DEBUG, "can_tx AESCBC (idx=%u)", (unsigned int)N2N_TRANSOP_AESCBC_IDX);
*trop = N2N_TRANSOP_AESCBC_IDX;
}
return tst;
}
/* ************************************** */
static n2n_tostat_t n2n_tick_twofish(n2n_edge_t * eee, time_t now, size_t *trop) {
n2n_tostat_t tst = (eee->transop[N2N_TRANSOP_TF_IDX].tick)(&(eee->transop[N2N_TRANSOP_TF_IDX]), now);
if(tst.can_tx)
{
traceEvent(TRACE_DEBUG, "can_tx TF (idx=%u)", (unsigned int)N2N_TRANSOP_TF_IDX);
*trop = N2N_TRANSOP_TF_IDX;
}
return tst;
} }
/* ************************************** */ /* ************************************** */
/** Called periodically to roll keys and do any periodic maintenance in the /** Called periodically to roll keys and do any periodic maintenance in the
* tranform operations state machines. */ * tranform operations state machines. */
static int n2n_tick_transop(n2n_edge_t * eee, time_t now) static int n2n_tick_transop(n2n_edge_t *eee, time_t now) {
{ n2n_tostat_t tst = eee->transop.tick(&eee->transop, now);
size_t trop = eee->tx_transop_idx;
/* Tests are done in order that most preferred transform is last and causes
* tx_transop_idx to be left at most preferred valid transform. */
(eee->transop[N2N_TRANSOP_NULL_IDX].tick)(&(eee->transop[N2N_TRANSOP_NULL_IDX]), now);
if(eee->preferred_aes) {
n2n_tick_twofish(eee, now, &trop);
n2n_tick_aes(eee, now, &trop);
} else {
n2n_tick_aes(eee, now, &trop);
n2n_tick_twofish(eee, now, &trop);
}
if(trop != eee->tx_transop_idx) if(!tst.can_tx) {
{ traceEvent(TRACE_ERROR, "transop.tick can_tx=0, no packets can be sent!");
eee->tx_transop_idx = trop; return(-1);
traceEvent(TRACE_INFO, "Chose new tx_transop_idx=%u", (unsigned int)(eee->tx_transop_idx));
} }
return 0; return 0;
@ -751,29 +760,6 @@ static int n2n_tick_transop(n2n_edge_t * eee, time_t now)
/* ************************************** */ /* ************************************** */
/** Find the transop op-struct for the transform enumeration required.
*
* @return - index into the transop array, or -1 on failure.
*/
static int transop_enum_to_index(n2n_transform_t id) {
switch (id)
{
case N2N_TRANSFORM_ID_TWOFISH:
return N2N_TRANSOP_TF_IDX;
break;
case N2N_TRANSFORM_ID_NULL:
return N2N_TRANSOP_NULL_IDX;
break;
case N2N_TRANSFORM_ID_AESCBC:
return N2N_TRANSOP_AESCBC_IDX;
break;
default:
return -1;
}
}
/* ************************************** */
/** A PACKET has arrived containing an encapsulated ethernet datagram - usually /** A PACKET has arrived containing an encapsulated ethernet datagram - usually
* encrypted. */ * encrypted. */
static int handle_PACKET(n2n_edge_t * eee, static int handle_PACKET(n2n_edge_t * eee,
@ -816,20 +802,19 @@ static int handle_PACKET(n2n_edge_t * eee,
{ {
uint8_t decodebuf[N2N_PKT_BUF_SIZE]; uint8_t decodebuf[N2N_PKT_BUF_SIZE];
size_t eth_size; size_t eth_size;
int rx_transop_idx; n2n_transform_id_t rx_transop_id;
rx_transop_idx = transop_enum_to_index(pkt->transform); rx_transop_id = (n2n_transform_id_t)pkt->transform;
if(rx_transop_idx >=0) if(rx_transop_id == eee->conf.transop_id) {
{
eth_payload = decodebuf; eth_payload = decodebuf;
eh = (ether_hdr_t*)eth_payload; eh = (ether_hdr_t*)eth_payload;
eth_size = eee->transop[rx_transop_idx].rev(&(eee->transop[rx_transop_idx]), eth_size = eee->transop.rev(&eee->transop,
eth_payload, N2N_PKT_BUF_SIZE, eth_payload, N2N_PKT_BUF_SIZE,
payload, psize, pkt->srcMac); payload, psize, pkt->srcMac);
++(eee->transop[rx_transop_idx].rx_cnt); /* stats */ ++(eee->transop.rx_cnt); /* stats */
if(!(eee->allow_routing)) { if(!(eee->conf.allow_routing)) {
if(ntohs(eh->type) == 0x0800) { if(ntohs(eh->type) == 0x0800) {
uint32_t *dst = (uint32_t*)&eth_payload[ETH_FRAMESIZE + IP4_DSTOFFSET]; uint32_t *dst = (uint32_t*)&eth_payload[ETH_FRAMESIZE + IP4_DSTOFFSET];
@ -857,8 +842,8 @@ static int handle_PACKET(n2n_edge_t * eee,
} }
else else
{ {
traceEvent(TRACE_ERROR, "handle_PACKET dropped unknown transform enum %u", traceEvent(TRACE_ERROR, "invalid transop ID: %u, expected %u",
(unsigned int)pkt->transform); rx_transop_id, eee->conf.transop_id);
} }
} }
@ -966,7 +951,7 @@ static void readFromMgmtSocket(n2n_edge_t * eee, int * keep_running) {
{ {
if(0 == memcmp(udp_buf, "reload", 6)) if(0 == memcmp(udp_buf, "reload", 6))
{ {
if(strlen(eee->keyschedule) > 0) if(strlen(eee->conf.keyschedule) > 0)
{ {
if(edge_init_keyschedule(eee) == 0) if(edge_init_keyschedule(eee) == 0)
{ {
@ -999,15 +984,9 @@ static void readFromMgmtSocket(n2n_edge_t * eee, int * keep_running) {
(unsigned int)eee->rx_p2p); (unsigned int)eee->rx_p2p);
msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
"trans:null |%6u|%6u|\n" "transop |%6u|%6u|\n",
"trans:tf |%6u|%6u|\n" (unsigned int)eee->transop.tx_cnt,
"trans:aes |%6u|%6u|\n", (unsigned int)eee->transop.rx_cnt);
(unsigned int)eee->transop[N2N_TRANSOP_NULL_IDX].tx_cnt,
(unsigned int)eee->transop[N2N_TRANSOP_NULL_IDX].rx_cnt,
(unsigned int)eee->transop[N2N_TRANSOP_TF_IDX].tx_cnt,
(unsigned int)eee->transop[N2N_TRANSOP_TF_IDX].rx_cnt,
(unsigned int)eee->transop[N2N_TRANSOP_AESCBC_IDX].tx_cnt,
(unsigned int)eee->transop[N2N_TRANSOP_AESCBC_IDX].rx_cnt);
msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len), msg_len += snprintf((char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
"peers pend:%u full:%u\n", "peers pend:%u full:%u\n",
@ -1071,25 +1050,6 @@ static int is_ethMulticast(const void * buf, size_t bufsize) {
/* ************************************** */ /* ************************************** */
/* Choose the transop for Tx. This should be based on the newest valid
* cipherspec in the key schedule.
*
* Never fall back to NULL tranform unless no key sources were specified. It is
* better to render edge inoperative than to expose user data in the clear. In
* the case where all SAs are expired an arbitrary transform will be chosen for
* Tx. It will fail having no valid SAs but one must be selected.
*/
static size_t edge_choose_tx_transop(const n2n_edge_t * eee) {
if(eee->null_transop)
{
return N2N_TRANSOP_NULL_IDX;
}
return eee->tx_transop_idx;
}
/* ************************************** */
/* @return 1 if destination is a peer, 0 if destination is supernode */ /* @return 1 if destination is a peer, 0 if destination is supernode */
static int find_peer_destination(n2n_edge_t * eee, static int find_peer_destination(n2n_edge_t * eee,
n2n_mac_t mac_address, n2n_mac_t mac_address,
@ -1173,7 +1133,7 @@ void send_packet2net(n2n_edge_t * eee,
uint8_t pktbuf[N2N_PKT_BUF_SIZE]; uint8_t pktbuf[N2N_PKT_BUF_SIZE];
size_t idx=0; size_t idx=0;
size_t tx_transop_idx=0; n2n_transform_t tx_transop_idx = eee->transop.transform_id;
ether_hdr_t eh; ether_hdr_t eh;
@ -1181,7 +1141,7 @@ void send_packet2net(n2n_edge_t * eee,
memcpy(&eh, tap_pkt, sizeof(ether_hdr_t)); memcpy(&eh, tap_pkt, sizeof(ether_hdr_t));
/* Discard IP packets that are not originated by this hosts */ /* Discard IP packets that are not originated by this hosts */
if(!(eee->allow_routing)) { if(!(eee->conf.allow_routing)) {
if(ntohs(eh.type) == 0x0800) { if(ntohs(eh.type) == 0x0800) {
/* This is an IP packet from the local source address - not forwarded. */ /* This is an IP packet from the local source address - not forwarded. */
uint32_t *src = (uint32_t*)&tap_pkt[ETH_FRAMESIZE + IP4_SRCOFFSET]; uint32_t *src = (uint32_t*)&tap_pkt[ETH_FRAMESIZE + IP4_SRCOFFSET];
@ -1209,26 +1169,24 @@ void send_packet2net(n2n_edge_t * eee,
cmn.ttl = N2N_DEFAULT_TTL; cmn.ttl = N2N_DEFAULT_TTL;
cmn.pc = n2n_packet; cmn.pc = n2n_packet;
cmn.flags=0; /* no options, not from supernode, no socket */ cmn.flags=0; /* no options, not from supernode, no socket */
memcpy(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE); memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE);
memset(&pkt, 0, sizeof(pkt)); memset(&pkt, 0, sizeof(pkt));
memcpy(pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); memcpy(pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE);
memcpy(pkt.dstMac, destMac, N2N_MAC_SIZE); memcpy(pkt.dstMac, destMac, N2N_MAC_SIZE);
tx_transop_idx = edge_choose_tx_transop(eee);
pkt.sock.family=0; /* do not encode sock */ pkt.sock.family=0; /* do not encode sock */
pkt.transform = eee->transop[tx_transop_idx].transform_id; pkt.transform = tx_transop_idx;
idx=0; idx=0;
encode_PACKET(pktbuf, &idx, &cmn, &pkt); encode_PACKET(pktbuf, &idx, &cmn, &pkt);
traceEvent(TRACE_DEBUG, "encoded PACKET header of size=%u transform %u (idx=%u)", traceEvent(TRACE_DEBUG, "encoded PACKET header of size=%u transform %u",
(unsigned int)idx, (unsigned int)pkt.transform, (unsigned int)tx_transop_idx); (unsigned int)idx, tx_transop_idx);
idx += eee->transop[tx_transop_idx].fwd(&(eee->transop[tx_transop_idx]), 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);
++(eee->transop[tx_transop_idx].tx_cnt); /* stats */ eee->transop.tx_cnt++; /* stats */
send_packet(eee, destMac, pktbuf, idx); /* to peer or supernode */ send_packet(eee, destMac, pktbuf, idx); /* to peer or supernode */
} }
@ -1269,7 +1227,7 @@ static void readFromTAPSocket(n2n_edge_t * eee) {
traceEvent(TRACE_INFO, "### Rx TAP packet (%4d) for %s", traceEvent(TRACE_INFO, "### Rx TAP packet (%4d) for %s",
(signed int)len, macaddr_str(mac_buf, mac)); (signed int)len, macaddr_str(mac_buf, mac));
if(eee->drop_multicast && if(eee->conf.drop_multicast &&
(is_ip6_discovery(eth_pkt, len) || (is_ip6_discovery(eth_pkt, len) ||
is_ethMulticast(eth_pkt, len) is_ethMulticast(eth_pkt, len)
) )
@ -1383,7 +1341,7 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
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(0 == memcmp(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE)) { if(0 == memcmp(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE)) {
if(msg_type == MSG_TYPE_PACKET) { if(msg_type == MSG_TYPE_PACKET) {
/* process PACKET - most frequent so first in list. */ /* process PACKET - most frequent so first in list. */
n2n_PACKET_t pkt; n2n_PACKET_t pkt;
@ -1614,7 +1572,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
(unsigned int)peer_list_size(eee->known_peers)); (unsigned int)peer_list_size(eee->known_peers));
} }
if(eee->dyn_ip_mode && if(eee->conf.dyn_ip_mode &&
((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) { ((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) {
traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address."); traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address.");
tuntap_get_address(&(eee->device)); tuntap_get_address(&(eee->device));
@ -1632,9 +1590,6 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
send_deregister(eee, &(eee->supernode)); send_deregister(eee, &(eee->supernode));
closesocket(eee->udp_sock); closesocket(eee->udp_sock);
tuntap_close(&(eee->device));
edge_term(eee);
return(0); return(0);
} }
@ -1648,7 +1603,8 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
* will then determine the best SA for that trans_op from the key schedule to * will then determine the best SA for that trans_op from the key schedule to
* use for encoding. */ * use for encoding. */
int edge_init_keyschedule(n2n_edge_t * eee) { // TODO call me
static int edge_init_keyschedule(n2n_edge_t *eee) {
#define N2N_NUM_CIPHERSPECS 32 #define N2N_NUM_CIPHERSPECS 32
int retval = -1; int retval = -1;
@ -1657,7 +1613,7 @@ int edge_init_keyschedule(n2n_edge_t * eee) {
size_t i; size_t i;
time_t now = time(NULL); time_t now = time(NULL);
numSpecs = n2n_read_keyfile(specs, N2N_NUM_CIPHERSPECS, eee->keyschedule); numSpecs = n2n_read_keyfile(specs, N2N_NUM_CIPHERSPECS, eee->conf.keyschedule);
if(numSpecs > 0) if(numSpecs > 0)
{ {
@ -1665,23 +1621,15 @@ int edge_init_keyschedule(n2n_edge_t * eee) {
for (i=0; i < (size_t)numSpecs; ++i) for (i=0; i < (size_t)numSpecs; ++i)
{ {
int idx; n2n_transform_t idx = (n2n_transform_t) specs[i].t;
if(idx != eee->transop.transform_id) {
idx = transop_enum_to_index(specs[i].t); traceEvent(TRACE_ERROR, "changing transop in keyschedule is not supported");
switch (idx)
{
case N2N_TRANSOP_TF_IDX:
case N2N_TRANSOP_AESCBC_IDX:
{
retval = (eee->transop[idx].addspec)(&(eee->transop[idx]),
&(specs[i]));
break;
}
default:
retval = -1; retval = -1;
} }
if(eee->transop.addspec != NULL)
retval = eee->transop.addspec(&eee->transop, &(specs[i]));
if (0 != retval) if (0 != retval)
{ {
traceEvent(TRACE_ERROR, "keyschedule failed to add spec[%u] to transop[%d].\n", traceEvent(TRACE_ERROR, "keyschedule failed to add spec[%u] to transop[%d].\n",
@ -1694,7 +1642,7 @@ int edge_init_keyschedule(n2n_edge_t * eee) {
n2n_tick_transop(eee, now); n2n_tick_transop(eee, now);
} }
else else
traceEvent(TRACE_ERROR, "Failed to process '%s'", eee->keyschedule); traceEvent(TRACE_ERROR, "Failed to process '%s'", eee->conf.keyschedule);
return retval; return retval;
} }
@ -1715,12 +1663,12 @@ void edge_term(n2n_edge_t * eee) {
clear_peer_list(&(eee->pending_peers)); clear_peer_list(&(eee->pending_peers));
clear_peer_list(&(eee->known_peers)); clear_peer_list(&(eee->known_peers));
(eee->transop[N2N_TRANSOP_TF_IDX].deinit)(&eee->transop[N2N_TRANSOP_TF_IDX]); eee->transop.deinit(&eee->transop);
(eee->transop[N2N_TRANSOP_NULL_IDX].deinit)(&eee->transop[N2N_TRANSOP_NULL_IDX]);
} }
/* ************************************** */ /* ************************************** */
// TODO check
const char *random_device_mac(void) const char *random_device_mac(void)
{ {
const char key[] = "0123456789abcdef"; const char key[] = "0123456789abcdef";
@ -1746,7 +1694,7 @@ const char *random_device_mac(void)
/* ************************************** */ /* ************************************** */
int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port) { static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port) {
/* Populate the multicast group for local edge */ /* Populate the multicast group for local edge */
eee->multicast_peer.family = AF_INET; eee->multicast_peer.family = AF_INET;
eee->multicast_peer.port = N2N_MULTICAST_PORT; eee->multicast_peer.port = N2N_MULTICAST_PORT;
@ -1755,6 +1703,9 @@ int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port) {
eee->multicast_peer.addr.v4[2] = 0; eee->multicast_peer.addr.v4[2] = 0;
eee->multicast_peer.addr.v4[3] = 68; eee->multicast_peer.addr.v4[3] = 68;
if(udp_local_port > 0)
traceEvent(TRACE_NORMAL, "Binding to local port %d", udp_local_port);
eee->udp_sock = open_socket(udp_local_port, 1 /* bind ANY */); eee->udp_sock = open_socket(udp_local_port, 1 /* bind ANY */);
if(eee->udp_sock < 0) { if(eee->udp_sock < 0) {
traceEvent(TRACE_ERROR, "Failed to bind main UDP port %u", udp_local_port); traceEvent(TRACE_ERROR, "Failed to bind main UDP port %u", udp_local_port);
@ -1799,28 +1750,53 @@ int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port) {
/* ************************************** */ /* ************************************** */
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port) {
if(conf->sn_num >= N2N_EDGE_NUM_SUPERNODES)
return(-1);
strncpy((conf->sn_ip_array[conf->sn_num]), ip_and_port, N2N_EDGE_SN_HOST_SIZE);
traceEvent(TRACE_NORMAL, "Adding supernode[%u] = %s", (unsigned int)conf->sn_num, (conf->sn_ip_array[conf->sn_num]));
conf->sn_num++;
return(0);
}
/* ************************************** */
int quick_edge_init(char *device_name, char *community_name, int quick_edge_init(char *device_name, char *community_name,
char *encrypt_key, char *device_mac, char *encrypt_key, char *device_mac,
char *local_ip_address, char *local_ip_address,
char *supernode_ip_address_port, char *supernode_ip_address_port,
int *keep_on_running) { int *keep_on_running) {
n2n_edge_t eee; tuntap_dev tuntap;
n2n_edge_t *eee;
edge_init(&eee); n2n_edge_conf_t conf;
int rv;
/* Setup the configuration */
edge_conf_init_defaults(&conf);
conf.encrypt_key = encrypt_key;
snprintf((char*)conf.community_name, sizeof(conf.community_name), "%s", community_name);
edge_conf_add_supernode(&conf, supernode_ip_address_port);
/* Validate configuration */
if(edge_verify_conf(&conf) != 0)
return(-1);
if(tuntap_open(&(eee.device), device_name, "static", /* Open the tuntap device */
if(tuntap_open(&tuntap, device_name, "static",
local_ip_address, "255.255.255.0", local_ip_address, "255.255.255.0",
device_mac, DEFAULT_MTU) < 0) device_mac, DEFAULT_MTU) < 0)
return(-1);
if(edge_init_encryption(&eee, (uint8_t *)encrypt_key, strlen(encrypt_key) < 0))
return(-2); return(-2);
snprintf((char*)eee.community_name, sizeof(eee.community_name), "%s", community_name); /* Init edge */
supernode2addr(&(eee.supernode), supernode_ip_address_port); if((eee = edge_init(&tuntap, &conf, &rv)) == NULL)
goto quick_edge_init_end;
if(edge_init_sockets(&eee, 0 /* ANY port */, 0 /* ANY port */) < 0) rv = run_edge_loop(eee, keep_on_running);
return(-3); edge_term(eee);
return(run_edge_loop(&eee, keep_on_running)); quick_edge_init_end:
tuntap_close(&tuntap);
return(rv);
} }

76
n2n.h

@ -174,64 +174,32 @@ struct peer_info {
time_t last_seen; time_t last_seen;
}; };
struct n2n_edge; /* defined in edge.c */
typedef struct n2n_edge n2n_edge_t;
#define N2N_EDGE_SN_HOST_SIZE 48 #define N2N_EDGE_SN_HOST_SIZE 48
#define N2N_EDGE_NUM_SUPERNODES 2 #define N2N_EDGE_NUM_SUPERNODES 2
#define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */ #define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */
#define N2N_PATHNAME_MAXLEN 256 #define N2N_PATHNAME_MAXLEN 256
#define N2N_MAX_TRANSFORMS 16
#define N2N_EDGE_MGMT_PORT 5644 #define N2N_EDGE_MGMT_PORT 5644
typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE]; typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];
struct n2n_edge {
int daemon; /**< Non-zero if edge should detach and run in the background. */
int preferred_aes; /**< Non-zero if AES is the preferred encryption meothd. */
uint8_t re_resolve_supernode_ip;
n2n_sock_t supernode;
size_t sn_idx; /**< Currently active supernode. */ typedef struct n2n_edge_conf {
size_t sn_num; /**< Number of supernode addresses defined. */ char keyschedule[N2N_PATHNAME_MAXLEN];
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES]; n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
int sn_wait; /**< Whether we are waiting for a supernode response. */
n2n_community_t community_name; /**< The community. 16 full octets. */ n2n_community_t community_name; /**< The community. 16 full octets. */
char keyschedule[N2N_PATHNAME_MAXLEN]; n2n_transform_id_t transop_id; /**< The transop to use. */
int null_transop; /**< Only allowed if no key sources defined. */ uint8_t re_resolve_supernode_ip;
uint8_t dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */
int udp_sock; uint8_t allow_routing; /**< Accept packet no to interface address. */
int udp_mgmt_sock; /**< socket for status info. */ uint8_t drop_multicast; /**< Multicast ethernet addresses. */
int udp_multicast_sock; /**< socket for local multicast registrations. */ uint8_t sn_num; /**< Number of supernode addresses defined. */
char *encrypt_key;
tuntap_dev device; /**< All about the TUNTAP device */ int local_port;
int dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */ int mgmt_port;
int allow_routing; /**< Accept packet no to interface address. */ } n2n_edge_conf_t;
int drop_multicast; /**< Multicast ethernet addresses. */
typedef struct n2n_edge n2n_edge_t; /* Opaque, see edge_utils.c */
n2n_trans_op_t transop[N2N_MAX_TRANSFORMS]; /* one for each transform at fixed positions */
size_t tx_transop_idx; /**< The transop to use when encoding. */
n2n_sock_t multicast_peer; /**< Multicast peer group (for local edges) */
struct peer_info * known_peers; /**< Edges we are connected to. */
struct peer_info * pending_peers; /**< Edges we have tried to register with. */
time_t last_register_req; /**< Check if time to re-register with super*/
size_t register_lifetime; /**< Time distance after last_register_req at which to re-register. */
time_t last_p2p; /**< Last time p2p traffic was received. */
time_t last_sup; /**< Last time a packet arrived from supernode. */
size_t sup_attempts; /**< Number of remaining attempts to this supernode. */
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
time_t start_time; /**< For calculating uptime */
/* Statistics */
size_t tx_p2p;
size_t rx_p2p;
size_t tx_sup;
size_t rx_sup;
};
/* ************************************** */ /* ************************************** */
@ -263,6 +231,13 @@ struct n2n_edge {
/* ************************************** */ /* ************************************** */
/* Transop Init Functions */
int n2n_transop_null_init(n2n_edge_t *eee, n2n_trans_op_t *op);
int n2n_transop_twofish_init(n2n_edge_t *eee, n2n_trans_op_t *op);
#ifdef N2N_HAVE_AES
int n2n_transop_aes_init(n2n_edge_t *eee, n2n_trans_op_t *op);
#endif
/* Log */ /* Log */
void setTraceLevel(int level); void setTraceLevel(int level);
void setUseSyslog(int use_syslog); void setUseSyslog(int use_syslog);
@ -312,14 +287,17 @@ void update_peer_address(n2n_edge_t * eee,
const n2n_sock_t * peer, const n2n_sock_t * peer,
time_t when); time_t when);
/* Edge conf */
void edge_conf_init_defaults(n2n_edge_conf_t *conf);
int edge_conf_add_supernode(n2n_edge_conf_t *conf, const char *ip_and_port);
/* Public functions */ /* Public functions */
int edge_init_keyschedule(n2n_edge_t * eee);
void send_packet2net(n2n_edge_t * eee, void send_packet2net(n2n_edge_t * eee,
uint8_t *tap_pkt, size_t len); uint8_t *tap_pkt, size_t len);
int edge_init_encryption(n2n_edge_t * eee, uint8_t *encrypt_pwd, uint32_t encrypt_pwd_len); int edge_init_encryption(n2n_edge_t * eee, uint8_t *encrypt_pwd, uint32_t encrypt_pwd_len);
int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port);
int edge_init(n2n_edge_t * eee); int edge_verify_conf(const n2n_edge_conf_t *conf);
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv);
void edge_term(n2n_edge_t *eee); void edge_term(n2n_edge_t *eee);
int run_edge_loop(n2n_edge_t * eee, int *keep_running); int run_edge_loop(n2n_edge_t * eee, int *keep_running);

52
n2n_transforms.h

@ -22,36 +22,30 @@
#include "n2n_keyfile.h" #include "n2n_keyfile.h"
#include "n2n_wire.h" #include "n2n_wire.h"
#define N2N_TRANSFORM_ID_INVAL 0 /* marks uninitialised data */
#define N2N_TRANSFORM_ID_NULL 1
#define N2N_TRANSFORM_ID_TWOFISH 2
#define N2N_TRANSFORM_ID_AESCBC 3
#define N2N_TRANSFORM_ID_LZO 4
#define N2N_TRANSFORM_ID_TWOFISH_LZO 5
#define N2N_TRANSFORM_ID_AESCBC_LZO 6
#define N2N_TRANSFORM_ID_USER_START 64 #define N2N_TRANSFORM_ID_USER_START 64
#define N2N_TRANSFORM_ID_MAX 65535 #define N2N_TRANSFORM_ID_MAX 65535
typedef enum n2n_transform_id {
N2N_TRANSFORM_ID_INVAL = 0,
N2N_TRANSFORM_ID_NULL = 1,
N2N_TRANSFORM_ID_TWOFISH = 2,
N2N_TRANSFORM_ID_AESCBC = 3,
} n2n_transform_id_t;
struct n2n_trans_op; struct n2n_trans_op;
typedef struct n2n_trans_op n2n_trans_op_t;
struct n2n_tostat { typedef struct n2n_tostat {
uint8_t can_tx; /* Does this transop have a valid SA for encoding. */ uint8_t can_tx; /* Does this transop have a valid SA for encoding. */
n2n_cipherspec_t tx_spec; /* If can_tx, the spec used to encode. */ n2n_cipherspec_t tx_spec; /* If can_tx, the spec used to encode. */
}; } n2n_tostat_t;
typedef struct n2n_tostat n2n_tostat_t;
typedef int (*n2n_transdeinit_f)( n2n_trans_op_t * arg ); typedef int (*n2n_transdeinit_f)( struct n2n_trans_op * arg );
typedef int (*n2n_transaddspec_f)( n2n_trans_op_t * arg, typedef int (*n2n_transaddspec_f)( struct n2n_trans_op * arg,
const n2n_cipherspec_t * cspec ); const n2n_cipherspec_t * cspec );
typedef n2n_tostat_t (*n2n_transtick_f)( n2n_trans_op_t * arg, typedef n2n_tostat_t (*n2n_transtick_f)( struct n2n_trans_op * arg,
time_t now ); time_t now );
typedef int (*n2n_transform_f)( n2n_trans_op_t * arg, typedef int (*n2n_transform_f)( struct n2n_trans_op * arg,
uint8_t * outbuf, uint8_t * outbuf,
size_t out_len, size_t out_len,
const uint8_t * inbuf, const uint8_t * inbuf,
@ -64,9 +58,9 @@ typedef int (*n2n_transform_f)( n2n_trans_op_t * arg,
* to use to decode the packet content. The transform code then decodes the * to use to decode the packet content. The transform code then decodes the
* packet and consults its internal key lookup. * packet and consults its internal key lookup.
*/ */
struct n2n_trans_op { typedef struct n2n_trans_op {
void * priv; /* opaque data. Key schedule goes here. */ void * priv; /* opaque data. Key schedule goes here. */
uint8_t no_encryption; /* 1 if this transop does not perform encryption */ // TODO
n2n_transform_t transform_id; /* link header enum to a transform */ n2n_transform_t transform_id; /* link header enum to a transform */
size_t tx_cnt; size_t tx_cnt;
size_t rx_cnt; size_t rx_cnt;
@ -76,23 +70,7 @@ struct n2n_trans_op {
n2n_transtick_f tick; /* periodic maintenance */ n2n_transtick_f tick; /* periodic maintenance */
n2n_transform_f fwd; /* encode a payload */ n2n_transform_f fwd; /* encode a payload */
n2n_transform_f rev; /* decode a payload */ n2n_transform_f rev; /* decode a payload */
}; } n2n_trans_op_t;
/* Setup a single twofish SA for single-key operation. */
int transop_twofish_setup_psk( n2n_trans_op_t * ttt,
n2n_sa_t sa_num,
uint8_t * encrypt_pwd,
uint32_t encrypt_pwd_len );
/* Setup a single AES SA for single-key operation. */
int transop_aes_setup_psk( n2n_trans_op_t * ttt,
n2n_sa_t sa_num,
uint8_t * encrypt_pwd,
uint32_t encrypt_pwd_len );
/* Initialise an empty transop ready to receive cipherspec elements. */
int transop_twofish_init( n2n_trans_op_t * ttt );
int transop_aes_init( n2n_trans_op_t * ttt );
void transop_null_init( n2n_trans_op_t * ttt );
#endif /* #if !defined(N2N_TRANSFORMS_H_) */ #endif /* #if !defined(N2N_TRANSFORMS_H_) */

Loading…
Cancel
Save