diff --git a/edge.c b/edge.c index e8d3cee..f55fb7e 100644 --- a/edge.c +++ b/edge.c @@ -324,11 +324,9 @@ static int setOption(int optkey, char *optargument, edge_conf_t *ec, n2n_edge_t } case 'v': /* verbose */ - { - ++traceLevel; /* do 2 -v flags to increase verbosity to DEBUG level*/ - break; - } - + traceLevel = 4; /* DEBUG */ + break; + default: { traceEvent(TRACE_WARNING, "Unknown option -%c: Ignored.", (char)optkey); @@ -679,19 +677,44 @@ int main(int argc, char* argv[]) { } /* else run in NULL mode */ + /* Populate the multicast group for local edge */ + eee.multicast_peer.family = AF_INET; + eee.multicast_peer.port = N2N_MULTICAST_PORT; + eee.multicast_peer.addr.v4[0] = 224; /* N2N_MULTICAST_GROUP */ + eee.multicast_peer.addr.v4[1] = 0; + eee.multicast_peer.addr.v4[2] = 0; + eee.multicast_peer.addr.v4[3] = 68; + eee.udp_sock = open_socket(ec.local_port, 1 /* bind ANY */); if(eee.udp_sock < 0) { traceEvent(TRACE_ERROR, "Failed to bind main UDP port %u", (signed int)ec.local_port); return(-1); } - eee.udp_mgmt_sock = open_socket(ec.mgmt_port, 0 /* bind LOOPBACK */); - + eee.udp_mgmt_sock = open_socket(eee.multicast_peer.port, 0 /* bind LOOPBACK */); if(eee.udp_mgmt_sock < 0) { traceEvent(TRACE_ERROR, "Failed to bind management UDP port %u", ec.mgmt_port); return(-1); + } else { + } - + + eee.udp_multicast_sock = open_socket(N2N_MULTICAST_PORT, 1 /* bind ANY */); + if(eee.udp_multicast_sock < 0) + return(-5); + else { + /* Bind eee.udp_multicast_sock to multicast group */ + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = inet_addr(N2N_MULTICAST_GROUP); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(eee.udp_multicast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { + traceEvent(TRACE_ERROR, "Failed to bind to local multicast group %s:%u", + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); + return(-6); + } + } + traceEvent(TRACE_NORMAL, "edge started"); update_supernode_reg(&eee, time(NULL)); diff --git a/edge_utils.c b/edge_utils.c index 548b88a..83f0096 100644 --- a/edge_utils.c +++ b/edge_utils.c @@ -77,6 +77,7 @@ int edge_init(n2n_edge_t * eee) { 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; @@ -177,36 +178,38 @@ void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) { static void try_send_register(n2n_edge_t * eee, uint8_t from_supernode, const n2n_mac_t mac, - const n2n_sock_t * peer) -{ + const n2n_sock_t * peer) { /* REVISIT: purge of pending_peers not yet done. */ struct peer_info * scan = find_peer_by_mac(eee->pending_peers, mac); macstr_t mac_buf; n2n_sock_str_t sockbuf; - if(NULL == scan) - { - scan = calloc(1, sizeof(struct peer_info)); + if(scan == NULL) { + scan = calloc(1, sizeof(struct peer_info)); - memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); - scan->sock = *peer; - scan->last_seen = time(NULL); /* Don't change this it marks the pending peer for removal. */ + memcpy(scan->mac_addr, mac, N2N_MAC_SIZE); + scan->sock = *peer; + scan->last_seen = time(NULL); /* Don't change this it marks the pending peer for removal. */ - peer_list_add(&(eee->pending_peers), scan); + peer_list_add(&(eee->pending_peers), scan); - traceEvent(TRACE_DEBUG, "=== new pending %s -> %s", - macaddr_str(mac_buf, scan->mac_addr), - sock_to_cstr(sockbuf, &(scan->sock))); + traceEvent(TRACE_DEBUG, "=== new pending %s -> %s", + macaddr_str(mac_buf, scan->mac_addr), + sock_to_cstr(sockbuf, &(scan->sock))); - traceEvent(TRACE_INFO, "Pending peers list size=%u", - (unsigned int)peer_list_size(eee->pending_peers)); + traceEvent(TRACE_INFO, "Pending peers list size=%u", + (unsigned int)peer_list_size(eee->pending_peers)); - /* trace Sending REGISTER */ + /* trace Sending REGISTER */ - send_register(eee, &(scan->sock)); + send_register(eee, &(scan->sock)); - /* pending_peers now owns scan. */ - } else { + /* no send registration to the local multicast group */ + traceEvent(TRACE_INFO, "Registering with multicast group %s:%u", + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); + send_register(eee, &(eee->multicast_peer)); + + /* pending_peers now owns scan. */ } } @@ -218,17 +221,14 @@ void check_peer(n2n_edge_t * eee, const n2n_mac_t mac, const n2n_sock_t * peer) { struct peer_info * scan = find_peer_by_mac(eee->known_peers, mac); - - if(NULL == scan) - { - /* Not in known_peers - start the REGISTER process. */ - try_send_register(eee, from_supernode, mac, peer); - } - else - { - /* Already in known_peers. */ - update_peer_address(eee, from_supernode, mac, peer, time(NULL)); - } + + if(NULL == scan) { + /* Not in known_peers - start the REGISTER process. */ + try_send_register(eee, from_supernode, mac, peer); + } else { + /* Already in known_peers. */ + update_peer_address(eee, from_supernode, mac, peer, time(NULL)); + } } /* ************************************** */ @@ -470,9 +470,7 @@ static void send_register_super(n2n_edge_t * eee, memcpy(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE); for(idx=0; idx < N2N_COOKIE_SIZE; ++idx) - { - eee->last_cookie[idx] = rand() % 0xff; - } + eee->last_cookie[idx] = rand() % 0xff; memcpy(reg.cookie, eee->last_cookie, N2N_COOKIE_SIZE); reg.auth.scheme=0; /* No auth yet */ @@ -564,41 +562,31 @@ static void send_register_ack(n2n_edge_t * eee, * This is frequently called by the main loop. */ void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) { - if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->register_lifetime/10)))) - { - /* fall through */ - traceEvent(TRACE_DEBUG, "update_supernode_reg: doing fast retry."); + if(eee->sn_wait && (nowTime > (eee->last_register_req + (eee->register_lifetime/10)))) { + /* fall through */ + traceEvent(TRACE_DEBUG, "update_supernode_reg: doing fast retry."); + } else if(nowTime < (eee->last_register_req + eee->register_lifetime)) + return; /* Too early */ + + if(0 == eee->sup_attempts) { + /* Give up on that supernode and try the next one. */ + ++(eee->sn_idx); + + if (eee->sn_idx >= eee->sn_num) { + /* Got to end of list, go back to the start. Also works for list of one entry. */ + eee->sn_idx=0; } - else if(nowTime < (eee->last_register_req + eee->register_lifetime)) - { - return; /* Too early */ - } - - if(0 == eee->sup_attempts) - { - /* Give up on that supernode and try the next one. */ - ++(eee->sn_idx); - - if (eee->sn_idx >= eee->sn_num) - { - /* Got to end of list, go back to the start. Also works for list of one entry. */ - eee->sn_idx=0; - } - traceEvent(TRACE_WARNING, "Supernode not responding - moving to %u of %u", - (unsigned int)eee->sn_idx, (unsigned int)eee->sn_num); + traceEvent(TRACE_WARNING, "Supernode not responding - moving to %u of %u", + (unsigned int)eee->sn_idx, (unsigned int)eee->sn_num); - eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; - } + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; + } else - { - --(eee->sup_attempts); - } + --(eee->sup_attempts); if(eee->re_resolve_supernode_ip || (eee->sn_num > 1)) - { - supernode2addr(&(eee->supernode), eee->sn_ip_array[eee->sn_idx]); - } + supernode2addr(&(eee->supernode), eee->sn_ip_array[eee->sn_idx]); traceEvent(TRACE_DEBUG, "Registering with supernode (%s) (attempts left %u)", supernode_ip(eee), (unsigned int)eee->sup_attempts); @@ -786,8 +774,8 @@ static void readFromMgmtSocket(n2n_edge_t * eee, int * keep_running) { now = time(NULL); i = sizeof(sender_sock); - recvlen=recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, - (struct sockaddr *)&sender_sock, (socklen_t*)&i); + recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t*)&i); if(recvlen < 0) { @@ -1159,15 +1147,15 @@ static void readFromTAPSocket(n2n_edge_t * eee) { ssize_t len; #ifdef __ANDROID_NDK__ - if (uip_arp_len != 0) { - len = uip_arp_len; - memcpy(eth_pkt, uip_arp_buf, MIN(uip_arp_len, N2N_PKT_BUF_SIZE)); - traceEvent(TRACE_DEBUG, "ARP reply packet to send"); - } - else + if (uip_arp_len != 0) { + len = uip_arp_len; + memcpy(eth_pkt, uip_arp_buf, MIN(uip_arp_len, N2N_PKT_BUF_SIZE)); + traceEvent(TRACE_DEBUG, "ARP reply packet to send"); + } + else { #endif /* #ifdef __ANDROID_NDK__ */ - len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE ); + len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE ); #ifdef __ANDROID_NDK__ } #endif /* #ifdef __ANDROID_NDK__ */ @@ -1230,7 +1218,7 @@ static void startTunReadThread(n2n_edge_t *eee) { /* ************************************** */ /** Read a datagram from the main UDP socket to the internet. */ -static void readFromIPSocket(n2n_edge_t * eee) { +static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { n2n_common_t cmn; /* common fields in the packet header */ n2n_sock_str_t sockbuf1; @@ -1252,19 +1240,18 @@ static void readFromIPSocket(n2n_edge_t * eee) { size_t i; i = sizeof(sender_sock); - recvlen=recvfrom(eee->udp_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, - (struct sockaddr *)&sender_sock, (socklen_t*)&i); + recvlen = recvfrom(in_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/, + (struct sockaddr *)&sender_sock, (socklen_t*)&i); - if(recvlen < 0) - { - traceEvent(TRACE_ERROR, "recvfrom failed with %s", strerror(errno)); - - return; /* failed to receive data from UDP */ - } + if(recvlen < 0) { + traceEvent(TRACE_ERROR, "recvfrom failed with %s", strerror(errno)); + + return; /* failed to receive data from UDP */ + } /* REVISIT: when UDP/IPv6 is supported we will need a flag to indicate which * IP transport version the packet arrived on. May need to UDP sockets. */ - sender.family = AF_INET; /* udp_sock was opened PF_INET v4 */ + sender.family = AF_INET; /* UDP socket was opened PF_INET v4 */ sender.port = ntohs(sender_sock.sin_port); memcpy(&(sender.addr.v4), &(sender_sock.sin_addr.s_addr), IPV4_SIZE); @@ -1343,9 +1330,7 @@ static void readFromIPSocket(n2n_edge_t * eee) { decode_REGISTER_ACK(&ra, &cmn, udp_buf, &rem, &idx); if(ra.sock.family) - { - orig_sender = &(ra.sock); - } + orig_sender = &(ra.sock); traceEvent(TRACE_INFO, "Rx REGISTER_ACK src=%s dst=%s from peer %s (%s)", macaddr_str(mac_buf1, ra.srcMac), @@ -1422,7 +1407,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { time_t lastIfaceCheck=0; time_t lastTransop=0; #ifdef __ANDROID_NDK__ - time_t lastArpPeriod=0; + time_t lastArpPeriod=0; #endif #ifdef WIN32 @@ -1448,6 +1433,9 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { FD_SET(eee->udp_sock, &socket_mask); FD_SET(eee->udp_mgmt_sock, &socket_mask); max_sock = max(eee->udp_sock, eee->udp_mgmt_sock); + FD_SET(eee->udp_multicast_sock, &socket_mask); + max_sock = max(eee->udp_sock, eee->udp_multicast_sock); + #ifndef WIN32 FD_SET(eee->device.fd, &socket_mask); max_sock = max(max_sock, eee->device.fd); @@ -1459,49 +1447,51 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { nowTime=time(NULL); /* Make sure ciphers are updated before the packet is treated. */ - if((nowTime - lastTransop) > TRANSOP_TICK_INTERVAL) - { - lastTransop = nowTime; - - n2n_tick_transop(eee, nowTime); + if((nowTime - lastTransop) > TRANSOP_TICK_INTERVAL) { + lastTransop = nowTime; + + n2n_tick_transop(eee, nowTime); + } + + if(rc > 0) { + /* Any or all of the FDs could have input; check them all. */ + + if(FD_ISSET(eee->udp_sock, &socket_mask)) { + /* Read a cooked socket from the internet socket (unicast). Writes on the TAP + * socket. */ + readFromIPSocket(eee, eee->udp_sock); } - if(rc > 0) - { - /* Any or all of the FDs could have input; check them all. */ - - if(FD_ISSET(eee->udp_sock, &socket_mask)) - { - /* Read a cooked socket from the internet socket. Writes on the TAP - * socket. */ - readFromIPSocket(eee); - } + if(FD_ISSET(eee->udp_multicast_sock, &socket_mask)) { + /* Read a cooked socket from the internet socket (multicast). Writes on the TAP + * socket. */ + traceEvent(TRACE_WARNING, "**** Received packet from multicast socket ****"); + readFromIPSocket(eee, eee->udp_multicast_sock); + } #ifdef __ANDROID_NDK__ - if (uip_arp_len != 0) { - readFromTAPSocket(eee); - uip_arp_len = 0; - } + if (uip_arp_len != 0) { + readFromTAPSocket(eee); + uip_arp_len = 0; + } #endif /* #ifdef __ANDROID_NDK__ */ - if(FD_ISSET(eee->udp_mgmt_sock, &socket_mask)) { - /* Read a cooked socket from the internet socket. Writes on the TAP - * socket. */ - readFromMgmtSocket(eee, keep_running); - } + if(FD_ISSET(eee->udp_mgmt_sock, &socket_mask)) { + /* Read a cooked socket from the internet socket. Writes on the TAP + * socket. */ + readFromMgmtSocket(eee, keep_running); + } #ifndef WIN32 - if(FD_ISSET(eee->device.fd, &socket_mask)) { - /* Read an ethernet frame from the TAP socket. Write on the IP - * socket. */ - readFromTAPSocket(eee); - } -#endif + if(FD_ISSET(eee->device.fd, &socket_mask)) { + /* Read an ethernet frame from the TAP socket. Write on the IP + * socket. */ + readFromTAPSocket(eee); } +#endif + } /* Finished processing select data. */ - - update_supernode_reg(eee, nowTime); numPurged = purge_expired_registrations(&(eee->known_peers)); @@ -1521,10 +1511,10 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { } #ifdef __ANDROID_NDK__ - if ((nowTime - lastArpPeriod) > ARP_PERIOD_INTERVAL) { - uip_arp_timer(); - lastArpPeriod = nowTime; - } + if ((nowTime - lastArpPeriod) > ARP_PERIOD_INTERVAL) { + uip_arp_timer(); + lastArpPeriod = nowTime; + } #endif /* #ifdef __ANDROID_NDK__ */ } /* while */ @@ -1592,11 +1582,9 @@ int edge_init_keyschedule(n2n_edge_t * eee) { n2n_tick_transop(eee, now); } - else - { - traceEvent(TRACE_ERROR, "Failed to process '%s'", eee->keyschedule); - } - + else + traceEvent(TRACE_ERROR, "Failed to process '%s'", eee->keyschedule); + return retval; } @@ -1610,6 +1598,9 @@ void edge_term(n2n_edge_t * eee) { if(eee->udp_mgmt_sock >= 0) closesocket(eee->udp_mgmt_sock); + if(eee->udp_multicast_sock >= 0) + closesocket(eee->udp_multicast_sock); + clear_peer_list(&(eee->pending_peers)); clear_peer_list(&(eee->known_peers)); @@ -1621,26 +1612,26 @@ void edge_term(n2n_edge_t * eee) { const char *random_device_mac(void) { - const char key[] = "0123456789abcdef"; - static char mac[18]; - int i; - - srand(getpid()); - for (i = 0; i < sizeof(mac) - 1; ++i) { - if ((i + 1) % 3 == 0) { - mac[i] = ':'; - continue; - } + const char key[] = "0123456789abcdef"; + static char mac[18]; + int i; + + srand(getpid()); + for (i = 0; i < sizeof(mac) - 1; ++i) { + if ((i + 1) % 3 == 0) { + mac[i] = ':'; + continue; + } #ifdef WIN32 #define random() rand() #endif - mac[i] = key[random() % sizeof(key)]; + mac[i] = key[random() % sizeof(key)]; #ifdef WIN32 #undef random() #endif - } - mac[sizeof(mac) - 1] = '\0'; - return mac; + } + mac[sizeof(mac) - 1] = '\0'; + return mac; } /* ************************************** */ @@ -1669,11 +1660,26 @@ int quick_edge_init(char *device_name, char *community_name, if(eee.udp_sock < 0) return(-3); - eee.udp_mgmt_sock = open_socket(0 /* any port */, 0 /* bind LOOPBACK */); - + eee.udp_mgmt_sock = open_socket(0 /* any port */, 0 /* bind LOOPBACK */); if(eee.udp_mgmt_sock < 0) return(-4); + eee.udp_multicast_sock = open_socket(N2N_MULTICAST_PORT, 1 /* bind ANY */); + if(eee.udp_multicast_sock < 0) + return(-5); + else { + /* Bind eee.udp_multicast_sock to multicast group */ + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = inet_addr(N2N_MULTICAST_GROUP); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(eee.udp_multicast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { + traceEvent(TRACE_ERROR, "Failed to bind to local multicast group %s:%u", + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); + return(-6); + } + } + update_supernode_reg(&eee, time(NULL)); return(run_edge_loop(&eee, keep_on_running)); diff --git a/n2n.c b/n2n.c index bbda9e5..6c6b635 100644 --- a/n2n.c +++ b/n2n.c @@ -58,6 +58,7 @@ SOCKET open_socket(int local_port, int bind_any) { local_address.sin_family = AF_INET; local_address.sin_port = htons(local_port); local_address.sin_addr.s_addr = htonl(bind_any ? INADDR_ANY : INADDR_LOOPBACK); + if(bind(sock_fd,(struct sockaddr*) &local_address, sizeof(local_address)) == -1) { traceEvent(TRACE_ERROR, "Bind error on local port %u [%s]\n", local_port, strerror(errno)); return(-1); diff --git a/n2n.h b/n2n.h index 16b4a8c..3fe4292 100644 --- a/n2n.h +++ b/n2n.h @@ -199,6 +199,7 @@ struct n2n_edge { int udp_sock; int udp_mgmt_sock; /**< socket for status info. */ + int udp_multicast_sock; /**< socket for local multicast registrations. */ tuntap_dev device; /**< All about the TUNTAP device */ int dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */ @@ -207,7 +208,7 @@ struct n2n_edge { 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*/ diff --git a/n2n_wire.h b/n2n_wire.h index 88fa0ea..306e09e 100644 --- a/n2n_wire.h +++ b/n2n_wire.h @@ -42,6 +42,9 @@ #define N2N_PKT_BUF_SIZE 2048 #define N2N_SOCKBUF_SIZE 64 /* string representation of INET or INET6 sockets */ +#define N2N_MULTICAST_PORT 1968 +#define N2N_MULTICAST_GROUP "224.0.0.68" + typedef uint8_t n2n_community_t[N2N_COMMUNITY_SIZE]; typedef uint8_t n2n_mac_t[N2N_MAC_SIZE]; typedef uint8_t n2n_cookie_t[N2N_COOKIE_SIZE];