From 7fa0cc1e0ae48ce82ebd05b8fd08c2572272c946 Mon Sep 17 00:00:00 2001 From: Logan oos Even <46396513+Logan007@users.noreply.github.com> Date: Thu, 9 Sep 2021 14:07:29 +0545 Subject: [PATCH] added preferred socket handling (-e) (#765) --- edge.8 | 5 ++ include/n2n_define.h | 3 +- include/n2n_typedefs.h | 33 +++++++------ include/n2n_wire.h | 9 ++++ src/edge.c | 39 ++++++++++++++- src/edge_utils.c | 107 ++++++++++++++++++++++++++++------------- src/sn_utils.c | 47 ++++++++++++------ src/wire.c | 57 ++++++++++++++-------- 8 files changed, 216 insertions(+), 84 deletions(-) diff --git a/edge.8 b/edge.8 index 3ea09ae..8124933 100644 --- a/edge.8 +++ b/edge.8 @@ -44,6 +44,11 @@ TOS for packets, e.g. 0x48 for SSH like priority enable PMTU discovery, it can reduce fragmentation but causes connections to stall if not properly supported .TP +\fB\-e \fR<\fIlocal ip\fR> +advertises the provided local IP address as preferred, +useful if multicast peer detection is not available, e.g. +disabled on routers +.TP \fB\-S1\fR ... \fB\-S2\fR do not connect p2p, always use the supernode, \-S1 = via UDP, \-S2 = via TCP diff --git a/include/n2n_define.h b/include/n2n_define.h index b9cfc40..4467316 100644 --- a/include/n2n_define.h +++ b/include/n2n_define.h @@ -165,7 +165,8 @@ enum skip_add{SN_ADD = 0, SN_ADD_SKIP = 1, SN_ADD_ADDED = 2}; #define N2N_PRIVATE_PUBLIC_KEY_SIZE 32 #define N2N_USER_KEY_LINE_STARTER '*' #define N2N_MAC_SIZE 6 -#define N2N_COOKIE_SIZE 4 +#define N2N_REGULAR_REG_COOKIE 0x00000000 +#define N2N_LOCAL_REG_COOKIE 0x00000001 #define N2N_DESC_SIZE 16 #define N2N_PKT_BUF_SIZE 2048 #define N2N_SOCKBUF_SIZE 64 /* string representation of INET or INET6 sockets */ diff --git a/include/n2n_typedefs.h b/include/n2n_typedefs.h index 4863ccf..7146303 100644 --- a/include/n2n_typedefs.h +++ b/include/n2n_typedefs.h @@ -20,19 +20,12 @@ #define _N2N_TYPEDEFS_H_ - -typedef uint8_t n2n_community_t[N2N_COMMUNITY_SIZE]; -typedef uint8_t n2n_private_public_key_t[N2N_PRIVATE_PUBLIC_KEY_SIZE]; -typedef uint8_t n2n_mac_t[N2N_MAC_SIZE]; -typedef uint8_t n2n_cookie_t[N2N_COOKIE_SIZE]; -typedef uint8_t n2n_desc_t[N2N_DESC_SIZE]; -typedef char n2n_sock_str_t[N2N_SOCKBUF_SIZE]; /* tracing string buffer */ - -// those are definitely not typedefs (with a view to the filename) but neither are they defines -static const n2n_mac_t broadcast_mac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -static const n2n_mac_t multicast_mac = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */ -static const n2n_mac_t ipv6_multicast_mac = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; /* First 2 bytes are meaningful */ -static const n2n_mac_t null_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +typedef uint8_t n2n_community_t[N2N_COMMUNITY_SIZE]; +typedef uint8_t n2n_private_public_key_t[N2N_PRIVATE_PUBLIC_KEY_SIZE]; +typedef uint8_t n2n_mac_t[N2N_MAC_SIZE]; +typedef uint32_t n2n_cookie_t; +typedef uint8_t n2n_desc_t[N2N_DESC_SIZE]; +typedef char n2n_sock_str_t[N2N_SOCKBUF_SIZE]; /* tracing string buffer */ #if defined(_MSC_VER) || defined(__MINGW32__) @@ -125,6 +118,14 @@ typedef unsigned long in_addr_t; #pragma pack(push,1) #endif + +// those are definitely not typedefs (with a view to the filename) but neither are they defines +static const n2n_mac_t broadcast_mac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const n2n_mac_t multicast_mac = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */ +static const n2n_mac_t ipv6_multicast_mac = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; /* First 2 bytes are meaningful */ +static const n2n_mac_t null_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + #define ETH_ADDR_LEN 6 struct ether_hdr { @@ -328,7 +329,7 @@ typedef struct n2n_REGISTER { n2n_cookie_t cookie; /**< Link REGISTER and REGISTER_ACK */ n2n_mac_t srcMac; /**< MAC of registering party */ n2n_mac_t dstMac; /**< MAC of target edge */ - n2n_sock_t sock; /**< REVISIT: unused? */ + n2n_sock_t sock; /**< Supernode's view of edge socket OR edge's preferred local socket */ n2n_ip_subnet_t dev_addr; /**< IP address of the tuntap adapter. */ n2n_desc_t dev_desc; /**< Hint description correlated with the edge */ } n2n_REGISTER_t; @@ -408,6 +409,7 @@ typedef struct n2n_PEER_INFO { n2n_mac_t srcMac; n2n_mac_t mac; n2n_sock_t sock; + n2n_sock_t preferred_sock; SN_SELECTION_CRITERION_DATA_TYPE data; } n2n_PEER_INFO_t; @@ -426,6 +428,8 @@ struct peer_info { n2n_desc_t dev_desc; n2n_sock_t sock; SOCKET socket_fd; + n2n_sock_t preferred_sock; + time_t last_local_reg; n2n_cookie_t last_cookie; n2n_auth_t auth; int timeout; @@ -647,6 +651,7 @@ typedef struct n2n_edge_conf { int register_interval; /**< Interval for supernode registration, also used for UDP NAT hole punching. */ int register_ttl; /**< TTL for registration packet when UDP NAT hole punching through supernode. */ in_addr_t bind_address; /**< The address to bind to if provided (-b) */ + n2n_sock_t preferred_sock; /**< propagated local sock for better p2p in LAN (-e) */ int local_port; int mgmt_port; uint8_t connect_tcp; /** connection to supernode 0 = UDP; 1 = TCP */ diff --git a/include/n2n_wire.h b/include/n2n_wire.h index 4189153..55983e0 100644 --- a/include/n2n_wire.h +++ b/include/n2n_wire.h @@ -91,6 +91,15 @@ int decode_mac (n2n_mac_t out, size_t * rem, size_t * idx); +int encode_cookie (uint8_t * base, + size_t * idx, + const n2n_cookie_t c); + +int decode_cookie (n2n_cookie_t * out, + const uint8_t * base, + size_t * rem, + size_t * idx); + int encode_common (uint8_t * base, size_t * idx, const n2n_common_t * common); diff --git a/src/edge.c b/src/edge.c index 43486b6..581552e 100644 --- a/src/edge.c +++ b/src/edge.c @@ -178,7 +178,7 @@ static void help (int level) { "[-H] " "[-z] " "\n " - "[-S] " + "[-e ] [-S]" "\n\n tap device and " "[-a [static:|dhcp:][/]] " "\n overlay network " @@ -254,6 +254,8 @@ static void help (int level) { printf(" -D | enable PMTU discovery, it can reduce fragmentation but\n" " | causes connections to stall if not properly supported\n"); #endif + printf(" -e | advertises the provided local IP address as preferred,\n" + " | useful if multicast peer detection is not available\n"); printf(" -S1 ... -S2 | do not connect p2p, always use the supernode,\n" " | -S1 = via UDP" @@ -612,6 +614,25 @@ static int setOption (int optkey, char *optargument, n2n_tuntap_priv_config_t *e break; } + case 'e': { + if(optargument) { + in_addr_t address_tmp = inet_addr(optargument); + + memcpy(&(conf->preferred_sock.addr.v4), &(address_tmp), IPV4_SIZE); + + if(address_tmp == INADDR_NONE) { + traceEvent(TRACE_WARNING, "bad address for preferred local socket, skipping"); + conf->preferred_sock.family = AF_INVALID; + break; + } else { + conf->preferred_sock.family = AF_INET; + // port is set after parsing all cli parameters + } + } + + break; + } + case 't': { conf->mgmt_port = atoi(optargument); break; @@ -747,7 +768,11 @@ static int loadFromCLI (int argc, char *argv[], n2n_edge_conf_t *conf, n2n_tunta u_char c; while ((c = getopt_long(argc, argv, +<<<<<<< HEAD "k:a:c:Eu:g:m:M:s:d:l:p:fvhrt:i:I:J:P:S::DL:z::A::Hn:R:" +======= + "k:a:b:c:Eu:g:m:M:s:d:l:p:fvhrt:i:I:J:P:S::DL:z::A::Hn:R:e:" +>>>>>>> 9772d7b (first draft) #ifdef __linux__ "T:" #endif @@ -1042,6 +1067,18 @@ int main (int argc, char* argv[]) { if(conf.encrypt_key && !strcmp((char*)conf.community_name, conf.encrypt_key)) traceEvent(TRACE_WARNING, "community and encryption key must differ, otherwise security will be compromised"); + // so far, preferred local sock (-e) only works with a fixed port provided (-p) + if(conf.preferred_sock.family != AF_INVALID) { + conf.preferred_sock.port = conf.local_port; + if(conf.local_port == 0) { + traceEvent(TRACE_WARNING, "preferred local socket requires a port to be provided (-p), skipping"); + conf.preferred_sock.family = AF_INVALID; + in_addr_t address_tmp = INADDR_NONE; + memcpy(&(conf.preferred_sock.addr.v4), &(address_tmp), IPV4_SIZE); + } + } + + if((eee = edge_init(&conf, &rc)) == NULL) { traceEvent(TRACE_ERROR, "failed in edge_init"); exit(1); diff --git a/src/edge_utils.c b/src/edge_utils.c index d987f93..8124d0e 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -31,12 +31,13 @@ int resolve_check (n2n_resolve_parameter_t *param, uint8_t resolution_request, t int resolve_cancel_thread (n2n_resolve_parameter_t *param); static const char * supernode_ip (const n2n_edge_t * eee); -static void send_register (n2n_edge_t *eee, const n2n_sock_t *remote_peer, const n2n_mac_t peer_mac); +static void send_register (n2n_edge_t *eee, const n2n_sock_t *remote_peer, const n2n_mac_t peer_mac, n2n_cookie_t cookie); static void check_peer_registration_needed (n2n_edge_t *eee, uint8_t from_supernode, uint8_t via_multicast, const n2n_mac_t mac, + const n2n_cookie_t cookie, const n2n_ip_subnet_t *dev_addr, const n2n_desc_t *dev_desc, const n2n_sock_t *peer); @@ -59,23 +60,23 @@ static void check_known_peer_sock_change (n2n_edge_t *eee, int edge_verify_conf (const n2n_edge_conf_t *conf) { if(conf->community_name[0] == 0) - return(-1); + return -1; // REVISIT: are the following two conditions equal? if so, remove one. but note that sn_num is used elsewhere if(conf->sn_num == 0) - return(-2); + return -2; if(HASH_COUNT(conf->supernodes) == 0) - return(-5); + return -5; if(conf->register_interval < 1) - return(-3); + return -3; if(((conf->encrypt_key == NULL) && (conf->transop_id != N2N_TRANSFORM_ID_NULL)) || ((conf->encrypt_key != NULL) && (conf->transop_id == N2N_TRANSFORM_ID_NULL))) - return(-4); + return -4; - return(0); + return 0; } @@ -530,7 +531,7 @@ static void register_with_local_peers (n2n_edge_t * eee) { /* send registration to the local multicast group */ traceEvent(TRACE_DEBUG, "registering with multicast group %s:%u", N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); - send_register(eee, &(eee->multicast_peer), NULL); + send_register(eee, &(eee->multicast_peer), NULL, N2N_LOCAL_REG_COOKIE); } #else traceEvent(TRACE_DEBUG, "multicast peers discovery is disabled, skipping"); @@ -627,18 +628,18 @@ static void register_with_new_peer (n2n_edge_t *eee, (void *) (char *) &eee->conf.register_ttl, sizeof(eee->conf.register_ttl)); for(; alter > 0; alter--, sock.port++) { - send_register(eee, &sock, mac); + send_register(eee, &sock, mac, N2N_REGULAR_REG_COOKIE); } setsockopt(eee->sock, IPPROTO_IP, IP_TTL, (void *) (char *) &curTTL, sizeof(curTTL)); #endif } else { /* eee->conf.register_ttl <= 0 */ /* Normal STUN */ - send_register(eee, &(scan->sock), mac); + send_register(eee, &(scan->sock), mac, N2N_REGULAR_REG_COOKIE); } - send_register(eee, &(eee->curr_sn->sock), mac); + send_register(eee, &(eee->curr_sn->sock), mac, N2N_REGULAR_REG_COOKIE); } else { /* P2P register, send directly */ - send_register(eee, &(scan->sock), mac); + send_register(eee, &(scan->sock), mac, N2N_REGULAR_REG_COOKIE); } register_with_local_peers(eee); } else{ @@ -659,6 +660,7 @@ static void check_peer_registration_needed (n2n_edge_t *eee, uint8_t from_supernode, uint8_t via_multicast, const n2n_mac_t mac, + const n2n_cookie_t cookie, const n2n_ip_subnet_t *dev_addr, const n2n_desc_t *dev_desc, const n2n_sock_t *peer) { @@ -671,10 +673,13 @@ static void check_peer_registration_needed (n2n_edge_t *eee, if(scan == NULL ) { scan = find_peer_by_sock(peer, eee->known_peers); + // MAC change if(scan) { HASH_DEL(eee->known_peers, scan); memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); HASH_ADD_PEER(eee->known_peers, scan); + // reset last_local_reg to allow re-registration + scan->last_local_reg = 0; } } @@ -691,12 +696,14 @@ static void check_peer_registration_needed (n2n_edge_t *eee, if(via_multicast) scan->local = 1; - if((now - scan->last_seen) > 0 /* >= 1 sec */) { + if(((now - scan->last_seen) > 0 /* >= 1 sec */) + ||(cookie == N2N_LOCAL_REG_COOKIE)) { /* Don't register too often */ check_known_peer_sock_change(eee, from_supernode, via_multicast, mac, dev_addr, dev_desc, peer, now); } } } + /* ************************************** */ @@ -706,6 +713,7 @@ static void check_peer_registration_needed (n2n_edge_t *eee, */ static void peer_set_p2p_confirmed (n2n_edge_t * eee, const n2n_mac_t mac, + const n2n_cookie_t cookie, const n2n_sock_t * peer, time_t now) { @@ -716,6 +724,9 @@ static void peer_set_p2p_confirmed (n2n_edge_t * eee, HASH_FIND_PEER(eee->pending_peers, mac, scan); if(scan == NULL) { scan = find_peer_by_sock(peer, eee->pending_peers); + // in case of MAC change, reset last_local_reg to allow re-registration + if(scan) + scan->last_local_reg = 0; } if(scan) { @@ -727,12 +738,20 @@ static void peer_set_p2p_confirmed (n2n_edge_t * eee, free(scan); scan = scan_tmp; memcpy(scan->mac_addr, mac, sizeof(n2n_mac_t)); + // in case of MAC change, reset last_local_reg to allow re-registration + scan->last_local_reg = 0; } else { - scan->sock = *peer; + // ignore regular ACKs's socket update for a while if we have recently received a local (!) ACK + if(((now - scan->last_local_reg) > REGISTRATION_TIMEOUT) + ||(cookie == N2N_LOCAL_REG_COOKIE)) { + scan->sock = *peer; + } } HASH_ADD_PEER(eee->known_peers, scan); scan->last_p2p = now; + if(cookie == N2N_LOCAL_REG_COOKIE) + scan->last_local_reg = now; traceEvent(TRACE_DEBUG, "p2p connection established: %s [%s]", macaddr_str(mac_buf, mac), @@ -1159,12 +1178,17 @@ void send_register_super (n2n_edge_t *eee) { cmn.ttl = N2N_DEFAULT_TTL; cmn.pc = n2n_register_super; - cmn.flags = 0; + if(eee->conf.preferred_sock.family == (uint8_t)AF_INVALID) { + cmn.flags = 0; + } else { + cmn.flags = N2N_FLAGS_SOCKET; + memcpy(&(reg.sock), &(eee->conf.preferred_sock), sizeof(n2n_sock_t)); + } memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - memrnd(eee->curr_sn->last_cookie, N2N_COOKIE_SIZE); + eee->curr_sn->last_cookie = n2n_rand(); - memcpy(reg.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE); + reg.cookie = eee->curr_sn->last_cookie; reg.dev_addr.net_addr = ntohl(eee->device.ip_addr); reg.dev_addr.net_bitlen = mask2bitlen(ntohl(eee->device.device_mask)); memcpy(reg.dev_desc, eee->conf.dev_desc, N2N_DESC_SIZE); @@ -1282,7 +1306,8 @@ static int sort_supernodes (n2n_edge_t *eee, time_t now) { /** Send a REGISTER packet to another edge. */ static void send_register (n2n_edge_t * eee, const n2n_sock_t * remote_peer, - const n2n_mac_t peer_mac) { + const n2n_mac_t peer_mac, + const n2n_cookie_t cookie) { uint8_t pktbuf[N2N_PKT_BUF_SIZE]; size_t idx; @@ -1303,8 +1328,7 @@ static void send_register (n2n_edge_t * eee, cmn.flags = 0; memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); - idx = 0; - encode_uint32(reg.cookie, &idx, 123456789); + reg.cookie = cookie; idx = 0; encode_mac(reg.srcMac, &idx, eee->device.mac_addr); @@ -1358,7 +1382,7 @@ static void send_register_ack (n2n_edge_t * eee, memcpy(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE); memset(&ack, 0, sizeof(ack)); - memcpy(ack.cookie, reg->cookie, N2N_COOKIE_SIZE); + ack.cookie = reg->cookie; memcpy(ack.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); memcpy(ack.dstMac, reg->srcMac, N2N_MAC_SIZE); @@ -1510,7 +1534,7 @@ void update_supernode_reg (n2n_edge_t * eee, time_t now) { if(eee->sn_wait == 1) HASH_ITER(hh, eee->known_peers, peer, tmp_peer) if((now - peer->last_seen) > REGISTER_SUPER_INTERVAL_DFL) - send_register(eee, &(peer->sock), peer->mac_addr); + send_register(eee, &(peer->sock), peer->mac_addr, N2N_REGULAR_REG_COOKIE); eee->sn_wait = 1; @@ -1961,7 +1985,7 @@ static int check_query_peer_info (n2n_edge_t *eee, time_t now, n2n_mac_t mac) { } if(now - scan->last_sent_query > eee->conf.register_interval) { - send_register(eee, &(eee->curr_sn->sock), mac); + send_register(eee, &(eee->curr_sn->sock), mac, N2N_REGULAR_REG_COOKIE); send_query_peer(eee, scan->mac_addr); scan->last_sent_query = now; return(0); @@ -2123,7 +2147,6 @@ void edge_send_packet2net (n2n_edge_t * eee, memcpy(pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE); memcpy(pkt.dstMac, destMac, N2N_MAC_SIZE); - pkt.sock.family = 0; /* do not encode sock */ pkt.transform = tx_transop_idx; // compression needs to be tried before encode_PACKET is called for compression indication gets encoded there @@ -2430,7 +2453,7 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const /* Update the sender in peer table entry */ check_peer_registration_needed(eee, from_supernode, via_multicast, - pkt.srcMac, NULL, NULL, orig_sender); + pkt.srcMac, N2N_REGULAR_REG_COOKIE, NULL, NULL, orig_sender); handle_PACKET(eee, from_supernode, &pkt, orig_sender, udp_buf + idx, udp_size - idx); break; @@ -2471,9 +2494,10 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const * a valid channel. We still use check_peer_registration_needed below * to double check this. */ - traceEvent(TRACE_INFO, "[p2p] Rx REGISTER from %s [%s]", + traceEvent(TRACE_INFO, "[p2p] Rx REGISTER from %s [%s]%s", macaddr_str(mac_buf1, reg.srcMac), - sock_to_cstr(sockbuf1, &sender)); + sock_to_cstr(sockbuf1, &sender), + (reg.cookie == N2N_LOCAL_REG_COOKIE) ? " (local)" : ""); find_and_remove_peer(&eee->pending_peers, reg.srcMac); /* NOTE: only ACK to peers */ @@ -2485,7 +2509,7 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const } check_peer_registration_needed(eee, from_supernode, via_multicast, - reg.srcMac, ®.dev_addr, (const n2n_desc_t*)®.dev_desc, orig_sender); + reg.srcMac, reg.cookie, ®.dev_addr, (const n2n_desc_t*)®.dev_desc, orig_sender); break; } @@ -2505,13 +2529,17 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const if(is_valid_peer_sock(&ra.sock)) orig_sender = &(ra.sock); - traceEvent(TRACE_INFO, "Rx REGISTER_ACK from %s [%s] to %s via [%s]", + traceEvent(TRACE_INFO, "Rx REGISTER_ACK from %s [%s] to %s via [%s]%s", macaddr_str(mac_buf1, ra.srcMac), sock_to_cstr(sockbuf2, orig_sender), macaddr_str(mac_buf2, ra.dstMac), - sock_to_cstr(sockbuf1, &sender)); + sock_to_cstr(sockbuf1, &sender), + (ra.cookie == N2N_LOCAL_REG_COOKIE) ? " (local)" : ""); - peer_set_p2p_confirmed(eee, ra.srcMac, &sender, now); + + peer_set_p2p_confirmed(eee, ra.srcMac, + ra.cookie, + &sender, now); break; } @@ -2548,7 +2576,7 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const } } - if(memcmp(ra.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE)) { + if(ra.cookie != eee->curr_sn->last_cookie) { traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old cookie"); return; } @@ -2655,7 +2683,7 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const } } - if(memcmp(nak.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE)) { + if(nak.cookie != eee->curr_sn->last_cookie) { traceEvent(TRACE_DEBUG, "Rx REGISTER_SUPER_NAK with wrong or old cookie"); return; } @@ -2730,11 +2758,21 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const if(scan) { scan->sock = pi.sock; + traceEvent(TRACE_INFO, "Rx PEER_INFO %s can be found at [%s]", macaddr_str(mac_buf1, pi.mac), sock_to_cstr(sockbuf1, &pi.sock)); - send_register(eee, &scan->sock, scan->mac_addr); + if(cmn.flags & N2N_FLAGS_SOCKET) { + scan->preferred_sock = pi.preferred_sock; + send_register(eee, &scan->preferred_sock, scan->mac_addr, N2N_LOCAL_REG_COOKIE); + + traceEvent(TRACE_INFO, "%s has preferred local socket at [%s]", + macaddr_str(mac_buf1, pi.mac), + sock_to_cstr(sockbuf1, &pi.preferred_sock)); + } + + send_register(eee, &scan->sock, scan->mac_addr, N2N_REGULAR_REG_COOKIE); } else { traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s", @@ -3550,6 +3588,7 @@ void edge_init_conf_defaults (n2n_edge_conf_t *conf) { conf->bind_address = INADDR_ANY; /* any address */ conf->local_port = 0 /* any port */; + conf->preferred_sock.family = AF_INVALID; conf->mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */ conf->transop_id = N2N_TRANSFORM_ID_NULL; conf->header_encryption = HEADER_ENCRYPTION_NONE; diff --git a/src/sn_utils.c b/src/sn_utils.c index 3d062bb..c0e47fa 100644 --- a/src/sn_utils.c +++ b/src/sn_utils.c @@ -38,6 +38,7 @@ static int sendto_mgmt (n2n_sn_t *sss, static uint16_t reg_lifetime (n2n_sn_t *sss); static int update_edge (n2n_sn_t *sss, + const n2n_common_t* cmn, const n2n_REGISTER_SUPER_t* reg, struct sn_community *comm, const n2n_sock_t *sender_sock, @@ -982,6 +983,7 @@ static int handle_remote_auth (n2n_sn_t *sss, const n2n_auth_t *remote_auth, switch(remote_auth->scheme) { // we do not handle n2n_auth_none because the edge always edge always uses either id or user/password // auth_none is sn-internal only (skipping MAC/IP address spoofing protection) + case n2n_auth_none: case n2n_auth_simple_id: // zero_token answer memset(answer_auth, 0, sizeof(n2n_auth_t)); @@ -1020,6 +1022,7 @@ static int handle_remote_auth (n2n_sn_t *sss, const n2n_auth_t *remote_auth, /** Update the edge table with the details of the edge which contacted the * supernode. */ static int update_edge (n2n_sn_t *sss, + const n2n_common_t* cmn, const n2n_REGISTER_SUPER_t* reg, struct sn_community *comm, const n2n_sock_t *sender_sock, @@ -1063,8 +1066,13 @@ static int update_edge (n2n_sn_t *sss, memcpy((char*)scan->dev_desc, reg->dev_desc, N2N_DESC_SIZE); memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); scan->socket_fd = socket_fd; - memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); + scan->last_cookie = reg->cookie; scan->last_valid_time_stamp = initial_time_stamp(); + // eventually, store edge's preferred local socket from REGISTER_SUPER + if(cmn->flags & N2N_FLAGS_SOCKET) + memcpy(&scan->preferred_sock, ®->sock, sizeof(n2n_sock_t)); + else + scan->preferred_sock.family = AF_INVALID; // store the submitted auth token memcpy(&(scan->auth), &(reg->auth), sizeof(n2n_auth_t)); @@ -1090,14 +1098,19 @@ static int update_edge (n2n_sn_t *sss, if(!sock_equal(sender_sock, &(scan->sock))) { memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t)); scan->socket_fd = socket_fd; - memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); + scan->last_cookie = reg->cookie; + // eventually, update edge's preferred local socket from REGISTER_SUPER + if(cmn->flags & N2N_FLAGS_SOCKET) + memcpy(&scan->preferred_sock, ®->sock, sizeof(n2n_sock_t)); + else + scan->preferred_sock.family = AF_INVALID; traceEvent(TRACE_INFO, "updated edge %s ==> %s", macaddr_str(mac_buf, reg->edgeMac), sock_to_cstr(sockbuf, sender_sock)); ret = update_edge_sock_change; } else { - memcpy(&(scan->last_cookie), reg->cookie, sizeof(N2N_COOKIE_SIZE)); + scan->last_cookie = reg->cookie; traceEvent(TRACE_DEBUG, "edge unchanged %s ==> %s", macaddr_str(mac_buf, reg->edgeMac), @@ -1355,9 +1368,8 @@ static int re_register_and_purge_supernodes (n2n_sn_t *sss, struct sn_community cmn.flags = N2N_FLAGS_FROM_SUPERNODE; memcpy(cmn.community, comm->community, N2N_COMMUNITY_SIZE); - memrnd(cookie, N2N_COOKIE_SIZE); - memcpy(reg.cookie, cookie, N2N_COOKIE_SIZE); - memcpy(peer->last_cookie, cookie, N2N_COOKIE_SIZE); + reg.cookie = n2n_rand(); + peer->last_cookie = reg.cookie; reg.dev_addr.net_addr = ntohl(peer->dev_addr.net_addr); reg.dev_addr.net_bitlen = mask2bitlen(ntohl(peer->dev_addr.net_bitlen)); @@ -2075,7 +2087,7 @@ static int process_udp (n2n_sn_t * sss, cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE; memcpy(cmn2.community, cmn.community, sizeof(n2n_community_t)); - memcpy(&(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t)); + ack.cookie = reg.cookie; memcpy(ack.srcMac, sss->mac_addr, sizeof(n2n_mac_t)); if(comm->is_federation != IS_FEDERATION) { /* alternatively, do not send zero tap ip address in federation REGISTER_SUPER */ @@ -2115,7 +2127,7 @@ static int process_udp (n2n_sn_t * sss, skip--; continue; } - if(peer->sock.family == AF_INVALID) + if(peer->sock.family == (uint8_t)AF_INVALID) continue; /* do not add unresolved supernodes to payload */ if(memcmp(&(peer->sock), &(ack.sock), sizeof(n2n_sock_t)) == 0) continue; /* a supernode doesn't add itself to the payload */ if((now - peer->last_seen) >= LAST_SEEN_SN_NEW) continue; /* skip long-time-not-seen supernodes. @@ -2136,18 +2148,18 @@ static int process_udp (n2n_sn_t * sss, // check authentication ret_value = update_edge_no_change; if(comm->is_federation != IS_FEDERATION) { /* REVISIT: auth among supernodes is not implemented yet */ - if(cmn.flags & N2N_FLAGS_SOCKET) { - ret_value = update_edge(sss, ®, comm, &(ack.sock), socket_fd, &(ack.auth), SN_ADD_SKIP, now); + if(cmn.flags & N2N_FLAGS_FROM_SUPERNODE) { + ret_value = update_edge(sss, &cmn, ®, comm, &(ack.sock), socket_fd, &(ack.auth), SN_ADD_SKIP, now); } else { // do not add in case of null mac (edge asking for ip address) - ret_value = update_edge(sss, ®, comm, &(ack.sock), socket_fd, &(ack.auth), is_null_mac(reg.edgeMac) ? SN_ADD_SKIP : SN_ADD, now); + ret_value = update_edge(sss, &cmn, ®, comm, &(ack.sock), socket_fd, &(ack.auth), is_null_mac(reg.edgeMac) ? SN_ADD_SKIP : SN_ADD, now); } } if(ret_value == update_edge_auth_fail) { // send REGISTER_SUPER_NAK cmn2.pc = n2n_register_super_nak; - memcpy(&(nak.cookie), &(reg.cookie), sizeof(n2n_cookie_t)); + nak.cookie = reg.cookie; memcpy(nak.srcMac, reg.edgeMac, sizeof(n2n_mac_t)); encode_REGISTER_SUPER_NAK(ackbuf, &encx, &cmn2, &nak); @@ -2166,8 +2178,9 @@ static int process_udp (n2n_sn_t * sss, traceEvent(TRACE_DEBUG, "Tx REGISTER_SUPER_NAK for %s", macaddr_str(mac_buf, reg.edgeMac)); } else { - // if this is not already forwarded from a supernode, ... - if(!(cmn.flags & N2N_FLAGS_SOCKET)) { + // if this is not already from a supernode ... + // and not from federation, ... + if((!(cmn.flags & N2N_FLAGS_FROM_SUPERNODE)) || (!(cmn.flags & N2N_FLAGS_SOCKET))) { // ... forward to all other supernodes (note try_broadcast()'s behavior with // NULL comm and from_supernode parameter) // exception: do not forward auto ip draw @@ -2360,7 +2373,7 @@ static int process_udp (n2n_sn_t * sss, break; } - if(0 == memcmp(ack.cookie, scan->last_cookie, N2N_COOKIE_SIZE)) { + if(ack.cookie == scan->last_cookie) { payload = (n2n_REGISTER_SUPER_ACK_payload_t *)dec_tmpbuf; for(i = 0; i < ack.num_sn; i++) { @@ -2568,6 +2581,10 @@ static int process_udp (n2n_sn_t * sss, memcpy(pi.srcMac, query.srcMac, sizeof(n2n_mac_t)); memcpy(pi.mac, query.targetMac, sizeof(n2n_mac_t)); pi.sock = scan->sock; + if(scan->preferred_sock.family != (uint8_t)AF_INVALID) { + cmn2.flags |= N2N_FLAGS_SOCKET; + pi.preferred_sock = scan->preferred_sock; + } encode_PEER_INFO(encbuf, &encx, &cmn2, &pi); diff --git a/src/wire.c b/src/wire.c index c018eb0..1579f39 100644 --- a/src/wire.c +++ b/src/wire.c @@ -171,15 +171,14 @@ int decode_buf (uint8_t * out, } - -int encode_mac (uint8_t * base, +int encode_mac (uint8_t * base, /* n2n_mac_t is typedefed array type which is always passed by reference */ size_t * idx, const n2n_mac_t m) { return encode_buf(base, idx, m, N2N_MAC_SIZE); } -int decode_mac (n2n_mac_t out, /* n2n_mac_t is typedefed array type which is always passed by reference */ +int decode_mac (n2n_mac_t out, const uint8_t * base, size_t * rem, size_t * idx) { @@ -187,6 +186,20 @@ int decode_mac (n2n_mac_t out, /* n2n_mac_t is typedefed array type which is alw return decode_buf(out, N2N_MAC_SIZE, base, rem, idx); } +int encode_cookie (uint8_t * base, + size_t * idx, + const n2n_cookie_t c) { + + return encode_uint32(base, idx, c); +} + +int decode_cookie (n2n_cookie_t * out, /* cookies are typedef'd as uint32_t which needs to correspond to this code */ + const uint8_t * base, + size_t * rem, + size_t * idx) { + + return decode_uint32(out, base, rem, idx); +} int encode_common (uint8_t * base, @@ -300,10 +313,10 @@ int encode_REGISTER (uint8_t *base, int retval = 0; retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); + retval += encode_cookie(base, idx, reg->cookie); retval += encode_mac(base, idx, reg->srcMac); retval += encode_mac(base, idx, reg->dstMac); - if(0 != reg->sock.family) { + if(common->flags & N2N_FLAGS_SOCKET) { retval += encode_sock(base, idx, &(reg->sock)); } retval += encode_uint32(base, idx, reg->dev_addr.net_addr); @@ -323,7 +336,7 @@ int decode_REGISTER (n2n_REGISTER_t *reg, size_t retval = 0; memset(reg, 0, sizeof(n2n_REGISTER_t)); - retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_cookie(®->cookie, base, rem, idx); retval += decode_mac(reg->srcMac, base, rem, idx); retval += decode_mac(reg->dstMac, base, rem, idx); if(cmn->flags & N2N_FLAGS_SOCKET) { @@ -345,9 +358,9 @@ int encode_REGISTER_SUPER (uint8_t *base, int retval = 0; retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); + retval += encode_cookie(base, idx, reg->cookie); retval += encode_mac(base, idx, reg->edgeMac); - if(0 != reg->sock.family) { + if(common->flags & N2N_FLAGS_SOCKET) { retval += encode_sock(base, idx, &(reg->sock)); } retval += encode_uint32(base, idx, reg->dev_addr.net_addr); @@ -371,7 +384,7 @@ int decode_REGISTER_SUPER (n2n_REGISTER_SUPER_t *reg, size_t retval = 0; memset(reg, 0, sizeof(n2n_REGISTER_SUPER_t)); - retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_cookie(®->cookie, base, rem, idx); retval += decode_mac(reg->edgeMac, base, rem, idx); if(cmn->flags & N2N_FLAGS_SOCKET) { retval += decode_sock(&(reg->sock), base, rem, idx); @@ -431,14 +444,14 @@ int encode_REGISTER_ACK (uint8_t *base, int retval = 0; retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); + retval += encode_cookie(base, idx, reg->cookie); retval += encode_mac(base, idx, reg->dstMac); retval += encode_mac(base, idx, reg->srcMac); /* The socket in REGISTER_ACK is the socket from which the REGISTER * arrived. This is sent back to the sender so it knows what its public * socket is. */ - if(0 != reg->sock.family) { + if(common->flags & N2N_FLAGS_SOCKET) { retval += encode_sock(base, idx, &(reg->sock)); } @@ -455,7 +468,7 @@ int decode_REGISTER_ACK (n2n_REGISTER_ACK_t *reg, size_t retval = 0; memset(reg, 0, sizeof(n2n_REGISTER_ACK_t)); - retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_cookie(®->cookie, base, rem, idx); retval += decode_mac(reg->dstMac, base, rem, idx); retval += decode_mac(reg->srcMac, base, rem, idx); @@ -479,7 +492,7 @@ int encode_REGISTER_SUPER_ACK (uint8_t *base, int retval = 0; retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, reg->cookie, N2N_COOKIE_SIZE); + retval += encode_cookie(base, idx, reg->cookie); retval += encode_mac(base, idx, reg->srcMac); retval += encode_uint32(base, idx, reg->dev_addr.net_addr); retval += encode_uint8(base, idx, reg->dev_addr.net_bitlen); @@ -510,7 +523,7 @@ int decode_REGISTER_SUPER_ACK (n2n_REGISTER_SUPER_ACK_t *reg, size_t retval = 0; memset(reg, 0, sizeof(n2n_REGISTER_SUPER_ACK_t)); - retval += decode_buf(reg->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_cookie(®->cookie, base, rem, idx); retval += decode_mac(reg->srcMac, base, rem, idx); retval += decode_uint32(&(reg->dev_addr.net_addr), base, rem, idx); retval += decode_uint8(&(reg->dev_addr.net_bitlen), base, rem, idx); @@ -541,7 +554,7 @@ int encode_REGISTER_SUPER_NAK (uint8_t *base, int retval = 0; retval += encode_common(base, idx, common); - retval += encode_buf(base, idx, nak->cookie, N2N_COOKIE_SIZE); + retval += encode_cookie(base, idx, nak->cookie); retval += encode_mac(base, idx, nak->srcMac); retval += encode_uint16(base, idx, nak->auth.scheme); @@ -561,7 +574,7 @@ int decode_REGISTER_SUPER_NAK (n2n_REGISTER_SUPER_NAK_t *nak, size_t retval = 0; memset(nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t)); - retval += decode_buf(nak->cookie, N2N_COOKIE_SIZE, base, rem, idx); + retval += decode_cookie(&nak->cookie, base, rem, idx); retval += decode_mac(nak->srcMac, base, rem, idx); retval += decode_uint16(&(nak->auth.scheme), base, rem, idx); @@ -602,7 +615,7 @@ int encode_PACKET (uint8_t * base, retval += encode_common(base, idx, common); retval += encode_mac(base, idx, pkt->srcMac); retval += encode_mac(base, idx, pkt->dstMac); - if(0 != pkt->sock.family) { + if(common->flags & N2N_FLAGS_SOCKET) { retval += encode_sock(base, idx, &(pkt->sock)); } retval += encode_uint8(base, idx, pkt->compression); @@ -637,16 +650,19 @@ int decode_PACKET (n2n_PACKET_t * pkt, int encode_PEER_INFO (uint8_t *base, size_t *idx, - const n2n_common_t *common, + const n2n_common_t *cmn, const n2n_PEER_INFO_t *pkt) { int retval = 0; - retval += encode_common(base, idx, common); + retval += encode_common(base, idx, cmn); retval += encode_uint16(base, idx, pkt->aflags); retval += encode_mac(base, idx, pkt->srcMac); retval += encode_mac(base, idx, pkt->mac); retval += encode_sock(base, idx, &pkt->sock); + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += encode_sock(base, idx, &pkt->preferred_sock); + } retval += encode_buf(base, idx, &pkt->data, sizeof(SN_SELECTION_CRITERION_DATA_TYPE)); return retval; @@ -666,6 +682,9 @@ int decode_PEER_INFO (n2n_PEER_INFO_t *pkt, retval += decode_mac(pkt->srcMac, base, rem, idx); retval += decode_mac(pkt->mac, base, rem, idx); retval += decode_sock(&pkt->sock, base, rem, idx); + if(cmn->flags & N2N_FLAGS_SOCKET) { + retval += decode_sock(&pkt->preferred_sock, base, rem, idx); + } retval += decode_buf((uint8_t*)&pkt->data, sizeof(SN_SELECTION_CRITERION_DATA_TYPE), base, rem, idx); return retval;