diff --git a/doc/HACKING b/doc/HACKING index 8a86a03..8b04ed1 100644 --- a/doc/HACKING +++ b/doc/HACKING @@ -35,10 +35,22 @@ socket to which the initiating UDP packets were sent. This means that when an inside host sends UDP to some outside socket; other hosts cannot piggyback on this opening in the firewall to send data to the inside host. -When two inside hosts are both behind symmetric NAT, peer-to-peer packet -exchange is not possible via n2n. These hosts will require the supernode to -relay packets. - +For example, an asymmetric NAT would keep the mapping: + -> +and would redirect all the packets on external port ExtPort to the internal host +regardless of the remote IP. + +Whereas a symmetric NAT would keep the mapping: + -> +so only RemoteIP can send packets to the internal host. RemoteIP is the supernode +IP in case of n2n, to which the internal host has registered. + +In n2n, P2P can work monodirecitonally if only one of the two peers is behind a symmetric +NAT. For example, if A is behind symmetric NAT and B is behind asymmetric NAT + - A->B packets are P2P (will have the B public IP as destination) + - B->A packets must go through the supernode + +If both the peers are behind symmetric NAT, then no P2P communication is possible. ARP CACHE --------- diff --git a/edge.8 b/edge.8 index 5157653..0ef1c35 100644 --- a/edge.8 +++ b/edge.8 @@ -39,6 +39,12 @@ truncated to take the first 16 bytes. \-h write usage then exit. .TP +\-i +Supernode registration interval. It specifies the interval in seconds +between consecutive REGISTER_SUPER packets and it's used to keep NAT hole +open via the UDP NAT hole punching technique. This only works for asymmetric +NATs and allows for P2P communication. +.TP \-k sets the twofish encryption key from ASCII text (see also N2N_KEY in ENVIRONMENT). All edges communicating must use the same key and community diff --git a/edge.c b/edge.c index 2cda0ba..ac07d74 100644 --- a/edge.c +++ b/edge.c @@ -120,7 +120,7 @@ static void help() { #endif /* #if defined(N2N_CAN_NAME_IFACE) */ "-a [static:|dhcp:] " "-c " - "[-k | -K ]\n" + "[-k ]\n" " " "[-s ] " #ifndef WIN32 @@ -134,7 +134,7 @@ static void help() { "-l \n" " " "[-p ] [-M ] " - "[-r] [-E] [-v] [-t ] [-b] [-A] [-h]\n\n"); + "[-r] [-E] [-v] [-i ] [-t ] [-b] [-A] [-h]\n\n"); #ifdef __linux__ printf("-d | tun device name\n"); @@ -145,6 +145,7 @@ static void help() { printf("-k | Encryption key (ASCII) - also N2N_KEY=.\n"); printf("-s | Edge interface netmask in dotted decimal notation (255.255.255.0).\n"); printf("-l | Supernode IP:port\n"); + printf("-i | Registration interval, for NAT hole punching (default 20 seconds)\n"); printf("-b | Periodically resolve supernode IP\n"); printf(" | (when supernodes are running on dynamic IPs)\n"); printf("-p | Fixed local UDP port.\n"); @@ -265,6 +266,10 @@ static int setOption(int optkey, char *optargument, n2n_priv_config_t *ec, n2n_e break; } + case 'i': /* supernode registration interval */ + conf->register_interval = atoi(optarg); + break; + #if defined(N2N_CAN_NAME_IFACE) case 'd': /* TUNTAP name */ { @@ -341,7 +346,7 @@ static int loadFromCLI(int argc, char *argv[], n2n_edge_conf_t *conf, n2n_priv_c u_char c; while((c = getopt_long(argc, argv, - "K:k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:" + "K:k:a:bc:Eu:g:m:M:s:d:l:p:fvhrt:i:" #ifdef N2N_HAVE_AES "A" #endif diff --git a/edge_utils.c b/edge_utils.c index 613bfa5..ed88fa4 100644 --- a/edge_utils.c +++ b/edge_utils.c @@ -28,16 +28,9 @@ #include #endif /* __ANDROID_NDK__ */ -#if defined(DEBUG) -#define SOCKET_TIMEOUT_INTERVAL_SECS 5 -#define REGISTER_SUPER_INTERVAL_DFL 20 /* sec */ -#else /* #if defined(DEBUG) */ -#define SOCKET_TIMEOUT_INTERVAL_SECS 10 -#define REGISTER_SUPER_INTERVAL_DFL 60 /* sec */ -#endif /* #if defined(DEBUG) */ -#define REGISTER_SUPER_INTERVAL_MIN 5 /* sec */ -#define REGISTER_SUPER_INTERVAL_MAX 3600 /* sec */ +#define SOCKET_TIMEOUT_INTERVAL_SECS 10 +#define REGISTER_SUPER_INTERVAL_DFL 20 /* sec, usually UDP NAT entries in a firewall expire after 30 seconds */ #define IFACE_UPDATE_INTERVAL (30) /* sec. How long it usually takes to get an IP lease. */ #define TRANSOP_TICK_INTERVAL (10) /* sec */ @@ -75,6 +68,9 @@ int edge_verify_conf(const n2n_edge_conf_t *conf) { if(conf->sn_num == 0) return(-2); + if(conf->register_interval < 1) + return(-3); + return(0); } @@ -104,7 +100,6 @@ struct n2n_edge { /* 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 */ @@ -151,7 +146,6 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r eee->known_peers = NULL; eee->pending_peers = NULL; - eee->register_lifetime = REGISTER_SUPER_INTERVAL_DFL; eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; #ifdef NOT_USED @@ -673,10 +667,10 @@ static void send_register_ack(n2n_edge_t * eee, static void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) { u_int sn_idx; - if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->register_lifetime/10)))) { + if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->conf.register_interval/10)))) { /* fall through */ traceEvent(TRACE_DEBUG, "update_supernode_reg: doing fast retry."); - } else if(nowTime < (eee->last_register_req + eee->register_lifetime)) + } else if(nowTime < (eee->last_register_req + eee->conf.register_interval)) return; /* Too early */ if(0 == eee->sup_attempts) { @@ -1403,10 +1397,9 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { eee->sn_wait=0; eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */ - /* REVISIT: store sn_back */ - eee->register_lifetime = ra.lifetime; - eee->register_lifetime = MAX(eee->register_lifetime, REGISTER_SUPER_INTERVAL_MIN); - eee->register_lifetime = MIN(eee->register_lifetime, REGISTER_SUPER_INTERVAL_MAX); + /* NOTE: the register_interval should be chosen by the edge node + * based on its NAT configuration. */ + //eee->conf.register_interval = ra.lifetime; } else { @@ -1639,6 +1632,7 @@ void edge_init_conf_defaults(n2n_edge_conf_t *conf) { 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; + conf->register_interval = REGISTER_SUPER_INTERVAL_DFL; if(getenv("N2N_KEY")) conf->encrypt_key = strdup(getenv("N2N_KEY")); diff --git a/n2n.h b/n2n.h index 6d6219f..4292a45 100644 --- a/n2n.h +++ b/n2n.h @@ -193,6 +193,7 @@ typedef struct n2n_edge_conf { uint8_t drop_multicast; /**< Multicast ethernet addresses. */ uint8_t sn_num; /**< Number of supernode addresses defined. */ char *encrypt_key; + int register_interval; /**< Interval for supernode registration, also used for UDP NAT hole punching. */ int local_port; int mgmt_port; } n2n_edge_conf_t;