diff --git a/android/edge_android.c b/android/edge_android.c index 00aec91..f502e2b 100644 --- a/android/edge_android.c +++ b/android/edge_android.c @@ -16,68 +16,17 @@ * */ -#include "../n2n.h" +#include "n2n.h" #ifdef __ANDROID_NDK__ -#include "edge_android.h" +#include #include #define N2N_NETMASK_STR_SIZE 16 /* dotted decimal 12 numbers + 3 dots */ #define N2N_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/ #define N2N_IF_MODE_SIZE 16 /* static | dhcp */ -/* *************************************************** */ - -#if defined(DUMMY_ID_00001) /* Disabled waiting for config option to enable it */ - -static char gratuitous_arp[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Dest mac */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */ - 0x08, 0x06, /* ARP */ - 0x00, 0x01, /* Ethernet */ - 0x08, 0x00, /* IP */ - 0x06, /* Hw Size */ - 0x04, /* Protocol Size */ - 0x00, 0x01, /* ARP Request */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */ - 0x00, 0x00, 0x00, 0x00, /* Src IP */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Target mac */ - 0x00, 0x00, 0x00, 0x00 /* Target IP */ -}; - -/* ************************************** */ - -/** Build a gratuitous ARP packet for a /24 layer 3 (IP) network. */ -static int build_gratuitous_arp(char *buffer, uint16_t buffer_len) { - if(buffer_len < sizeof(gratuitous_arp)) return(-1); - - memcpy(buffer, gratuitous_arp, sizeof(gratuitous_arp)); - memcpy(&buffer[6], device.mac_addr, 6); - memcpy(&buffer[22], device.mac_addr, 6); - memcpy(&buffer[28], &device.ip_addr, 4); - - /* REVISIT: BbMaj7 - use a real netmask here. This is valid only by accident - * for /24 IPv4 networks. */ - buffer[31] = 0xFF; /* Use a faked broadcast address */ - memcpy(&buffer[38], &device.ip_addr, 4); - return(sizeof(gratuitous_arp)); -} - -/* ************************************** */ - -/** Called from update_supernode_reg to periodically send gratuitous ARP - * broadcasts. */ -static void send_grat_arps(n2n_edge_t * eee,) { - char buffer[48]; - size_t len; - - traceEvent(TRACE_NORMAL, "Sending gratuitous ARP..."); - len = build_gratuitous_arp(buffer, sizeof(buffer)); - send_packet2net(eee, buffer, len); - send_packet2net(eee, buffer, len); /* Two is better than one :-) */ -} - -#endif /* #if defined(DUMMY_ID_00001) */ +n2n_edge_status_t* g_status; /* ***************************************************** */ @@ -98,201 +47,169 @@ static void send_grat_arps(n2n_edge_t * eee,) { * return 0 on success and -1 on error */ static int scan_address(char * ip_addr, size_t addr_size, - char * ip_mode, size_t mode_size, - const char * s) { - int retval = -1; - char * p; + char * ip_mode, size_t mode_size, + const char * s) { + int retval = -1; + char * p; - if((NULL == s) || (NULL == ip_addr)) + if((NULL == s) || (NULL == ip_addr)) { - return -1; + return -1; } - memset(ip_addr, 0, addr_size); + memset(ip_addr, 0, addr_size); - p = strpbrk(s, ":"); + p = strpbrk(s, ":"); - if(p) + if(p) { - /* colon is present */ - if(ip_mode) + /* colon is present */ + if(ip_mode) { - size_t end=0; + size_t end=0; - memset(ip_mode, 0, mode_size); - end = MIN(p-s, (ssize_t)(mode_size-1)); /* ensure NULL term */ - strncpy(ip_mode, s, end); - strncpy(ip_addr, p+1, addr_size-1); /* ensure NULL term */ - retval = 0; + memset(ip_mode, 0, mode_size); + end = MIN(p-s, (ssize_t)(mode_size-1)); /* ensure NULL term */ + strncpy(ip_mode, s, end); + strncpy(ip_addr, p+1, addr_size-1); /* ensure NULL term */ + retval = 0; } } - else + else { - /* colon is not present */ - strncpy(ip_addr, s, addr_size); + /* colon is not present */ + strncpy(ip_addr, s, addr_size); } - return retval; + return retval; } /* *************************************************** */ -//TODO use new API -int start_edge(const n2n_edge_cmd_t* cmd) +static 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; + } + mac[i] = key[random() % sizeof(key)]; + } + mac[sizeof(mac) - 1] = '\0'; + return mac; +} + +/* *************************************************** */ + +int start_edge_v2(n2n_edge_status_t* status) { int keep_on_running = 0; - int local_port = 0 /* any port */; char tuntap_dev_name[N2N_IFNAMSIZ] = "tun0"; char ip_mode[N2N_IF_MODE_SIZE]="static"; char ip_addr[N2N_NETMASK_STR_SIZE] = ""; char netmask[N2N_NETMASK_STR_SIZE]="255.255.255.0"; char device_mac[N2N_MACNAMSIZ]=""; char * encrypt_key=NULL; - n2n_edge_t eee; + struct in_addr gateway_ip = {0}; + n2n_edge_conf_t conf; + n2n_edge_t *eee = NULL; int i; + tuntap_dev dev; - keep_on_running = 0; - pthread_mutex_lock(&status.mutex); - status.is_running = keep_on_running; - pthread_mutex_unlock(&status.mutex); - report_edge_status(); - if (!cmd) { + if (!status) { traceEvent( TRACE_ERROR, "Empty cmd struct" ); return 1; } - - traceLevel = cmd->trace_vlevel; - traceLevel = traceLevel < 0 ? 0 : traceLevel; /* TRACE_ERROR */ - traceLevel = traceLevel > 4 ? 4 : traceLevel; /* TRACE_DEBUG */ - - /* Random seed */ - srand(time(NULL)); - - if (-1 == edge_init(&eee) ) - { - traceEvent( TRACE_ERROR, "Failed in edge_init" ); - return 1; - } - memset(&(eee.supernode), 0, sizeof(eee.supernode)); - eee.supernode.family = AF_INET; + g_status = status; + n2n_edge_cmd_t* cmd = &status->cmd; if (cmd->vpn_fd < 0) { traceEvent(TRACE_ERROR, "VPN socket is invalid."); return 1; } - eee.device.fd = cmd->vpn_fd; - if (cmd->enc_key) - { - encrypt_key = strdup(cmd->enc_key); + + pthread_mutex_lock(&g_status->mutex); + g_status->running_status = EDGE_STAT_CONNECTING; + pthread_mutex_unlock(&g_status->mutex); + g_status->report_edge_status(); + + edge_init_conf_defaults(&conf); + + /* Load the configuration */ + strncpy((char *)conf.community_name, cmd->community, N2N_COMMUNITY_SIZE-1); + + if(cmd->enc_key && cmd->enc_key[0]) { + conf.transop_id = N2N_TRANSFORM_ID_TWOFISH; + conf.encrypt_key = strdup(cmd->enc_key); traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", encrypt_key); } - if (cmd->ip_addr[0] != '\0') - { - scan_address(ip_addr, N2N_NETMASK_STR_SIZE, - ip_mode, N2N_IF_MODE_SIZE, - cmd->ip_addr); - } - else - { - traceEvent(TRACE_ERROR, "Ip address is not set."); - free(encrypt_key); - return 1; - } - if (cmd->community[0] != '\0') - { - strncpy((char *)eee.community_name, cmd->community, N2N_COMMUNITY_SIZE); - } - else - { - traceEvent(TRACE_ERROR, "Community is not set."); - free(encrypt_key); - return 1; - } - eee.drop_multicast = cmd->drop_multicast == 0 ? 0 : 1; - if (cmd->mac_addr[0] != '\0') - { - strncpy(device_mac, cmd->mac_addr, N2N_MACNAMSIZ); - } - else - { - strncpy(device_mac, random_device_mac(), N2N_MACNAMSIZ); - traceEvent(TRACE_DEBUG, "random device mac: %s\n", device_mac); - } - eee.allow_routing = cmd->allow_routing == 0 ? 0 : 1; + scan_address(ip_addr, N2N_NETMASK_STR_SIZE, + ip_mode, N2N_IF_MODE_SIZE, + cmd->ip_addr); + + dev.fd = cmd->vpn_fd; + + conf.drop_multicast = cmd->drop_multicast == 0 ? 0 : 1; + conf.allow_routing = cmd->allow_routing == 0 ? 0 : 1; + conf.dyn_ip_mode = (strcmp("dhcp", ip_mode) == 0) ? 1 : 0; + for (i = 0; i < N2N_EDGE_NUM_SUPERNODES && i < EDGE_CMD_SUPERNODES_NUM; ++i) { if (cmd->supernodes[i][0] != '\0') { - strncpy(eee.sn_ip_array[eee.sn_num], cmd->supernodes[i], N2N_EDGE_SN_HOST_SIZE); - traceEvent(TRACE_DEBUG, "Adding supernode[%u] = %s\n", (unsigned int)eee.sn_num, (eee.sn_ip_array[eee.sn_num])); - ++eee.sn_num; + strncpy(conf.sn_ip_array[conf.sn_num], cmd->supernodes[i], N2N_EDGE_SN_HOST_SIZE); + traceEvent(TRACE_DEBUG, "Adding supernode[%u] = %s\n", (unsigned int)conf.sn_num, (conf.sn_ip_array[conf.sn_num])); + ++conf.sn_num; } } - eee.re_resolve_supernode_ip = cmd->re_resolve_supernode_ip == 0 ? 0 : 1; + if (cmd->ip_netmask[0] != '\0') - { strncpy(netmask, cmd->ip_netmask, N2N_NETMASK_STR_SIZE); + + if (cmd->gateway_ip[0] != '\0') + inet_aton(cmd->gateway_ip, &gateway_ip); + + if (cmd->mac_addr[0] != '\0') + strncpy(device_mac, cmd->mac_addr, N2N_MACNAMSIZ); + else { + strncpy(device_mac, random_device_mac(), N2N_MACNAMSIZ); + traceEvent(TRACE_DEBUG, "random device mac: %s\n", device_mac); } - for (i=0; i< N2N_EDGE_NUM_SUPERNODES; ++i ) - { - traceEvent(TRACE_NORMAL, "supernode %u => %s\n", i, (eee.sn_ip_array[i])); + if(edge_verify_conf(&conf) != 0) { + if(conf.encrypt_key) free(conf.encrypt_key); + traceEvent(TRACE_ERROR, "Bad configuration"); + return 1; } - supernode2addr(&(eee.supernode), eee.sn_ip_array[eee.sn_idx]); - if (encrypt_key == NULL) - { - traceEvent(TRACE_WARNING, "Encryption is disabled in edge."); - eee.null_transop = 1; - } - if (0 == strcmp("dhcp", ip_mode)) - { - traceEvent(TRACE_NORMAL, "Dynamic IP address assignment enabled."); - eee.dyn_ip_mode = 1; - } - else - { - traceEvent(TRACE_NORMAL, "ip_mode='%s'", ip_mode); - } - if(tuntap_open(&(eee.device), tuntap_dev_name, ip_mode, ip_addr, netmask, device_mac, cmd->mtu) < 0) - { + + /* Open the TAP device */ + if(tuntap_open(&dev, tuntap_dev_name, ip_mode, ip_addr, netmask, device_mac, cmd->mtu) < 0) { traceEvent(TRACE_ERROR, "Failed in tuntap_open"); free(encrypt_key); return 1; } - if(local_port > 0) - { - traceEvent(TRACE_NORMAL, "Binding to local port %d", (signed int)local_port); - } - if (encrypt_key) - { - if(edge_init_twofish(&eee, (uint8_t *)(encrypt_key), strlen(encrypt_key)) < 0) - { - traceEvent(TRACE_ERROR, "twofish setup failed.\n"); - free(encrypt_key); - return 1; - } - free(encrypt_key); - encrypt_key = NULL; - } - /* else run in NULL mode */ - eee.udp_sock = open_socket(local_port, 1 /*bind ANY*/ ); - if(eee.udp_sock < 0) - { - traceEvent(TRACE_ERROR, "Failed to bind main UDP port %u", (signed int)local_port); - return 1; - } - eee.udp_mgmt_sock = open_socket(N2N_EDGE_MGMT_PORT, 0 /* bind LOOPBACK*/ ); - if(eee.udp_mgmt_sock < 0) - { - traceEvent( TRACE_ERROR, "Failed to bind management UDP port %u", (unsigned int)N2N_EDGE_MGMT_PORT ); + + /* Start n2n */ + eee = edge_init(&dev, &conf, &i); + + if(eee == NULL) { + traceEvent( TRACE_ERROR, "Failed in edge_init" ); return 1; } + /* Set runtime information */ + eee->gateway_ip = gateway_ip.s_addr; + /* set host addr, netmask, mac addr for UIP and init arp*/ { int match, i; - u8_t ip[4]; + int ip[4]; uip_ipaddr_t ipaddr; struct uip_eth_addr eaddr; @@ -311,7 +228,7 @@ int start_edge(const n2n_edge_cmd_t* cmd) uip_ipaddr(ipaddr, ip[0], ip[1], ip[2], ip[3]); uip_setnetmask(ipaddr); for (i = 0; i < 6; ++i) { - eaddr.addr[i] = eee.device.mac_addr[i]; + eaddr.addr[i] = eee->device.mac_addr[i]; } uip_setethaddr(eaddr); @@ -319,16 +236,27 @@ int start_edge(const n2n_edge_cmd_t* cmd) } keep_on_running = 1; - pthread_mutex_lock(&status.mutex); - status.is_running = keep_on_running; - pthread_mutex_unlock(&status.mutex); - report_edge_status(); + pthread_mutex_lock(&g_status->mutex); + g_status->running_status = EDGE_STAT_CONNECTED; + pthread_mutex_unlock(&g_status->mutex); + g_status->report_edge_status(); traceEvent(TRACE_NORMAL, "edge started"); - return run_edge_loop(&eee, &keep_on_running); + update_supernode_reg(eee, time(NULL)); + + run_edge_loop(eee, &keep_on_running); + + /* Cleanup */ + edge_term(eee); + tuntap_close(&dev); + edge_term_conf(&conf); + + traceEvent(TRACE_NORMAL, "Edge stopped"); + + return 0; } -int stop_edge(void) +int stop_edge_v2(void) { // quick stop int fd = open_socket(0, 0 /* bind LOOPBACK*/ ); @@ -341,12 +269,12 @@ int stop_edge(void) peer_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); peer_addr.sin_port = htons(N2N_EDGE_MGMT_PORT); sendto(fd, "stop", 4, 0, (struct sockaddr *)&peer_addr, sizeof(struct sockaddr_in)); - close(fd); + close(fd); - pthread_mutex_lock(&status.mutex); - status.is_running = 0; - pthread_mutex_unlock(&status.mutex); - report_edge_status(); + pthread_mutex_lock(&g_status->mutex); + g_status->running_status = EDGE_STAT_DISCONNECT; + pthread_mutex_unlock(&g_status->mutex); + g_status->report_edge_status(); return 0; } diff --git a/android/edge_android.h b/android/edge_android.h deleted file mode 100644 index d7dc503..0000000 --- a/android/edge_android.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// Created by switchwang(https://github.com/switch-st) on 2018-04-13. -// - -#ifndef _EDGE_ANDROID_H_ -#define _EDGE_ANDROID_H_ - -#ifdef __ANDROID_NDK__ - -#include "../n2n.h" -#include - -#define EDGE_CMD_IPSTR_SIZE 16 -#define EDGE_CMD_SUPERNODES_NUM 2 -#define EDGE_CMD_SN_HOST_SIZE 48 -#define EDGE_CMD_MACNAMSIZ 18 - - -typedef struct n2n_edge_cmd_st -{ - char ip_addr[EDGE_CMD_IPSTR_SIZE]; - char ip_netmask[EDGE_CMD_IPSTR_SIZE]; - char supernodes[EDGE_CMD_SUPERNODES_NUM][EDGE_CMD_SN_HOST_SIZE]; - char community[N2N_COMMUNITY_SIZE]; - char* enc_key; - char* enc_key_file; - char mac_addr[EDGE_CMD_MACNAMSIZ]; - unsigned int mtu; - int re_resolve_supernode_ip; - unsigned int local_port; - int allow_routing; - int drop_multicast; - int trace_vlevel; - int vpn_fd; -} n2n_edge_cmd_t; - -typedef struct n2n_edge_status_st -{ - pthread_mutex_t mutex; - uint8_t is_running; -} n2n_edge_status; - -#define INIT_EDGE_CMD(cmd) do {\ - memset(&(cmd), 0, sizeof((cmd))); \ - (cmd).enc_key = NULL; \ - (cmd).enc_key_file = NULL; \ - (cmd).mtu = 1400; \ - (cmd).re_resolve_supernode_ip = 0;\ - (cmd).local_port = 0; \ - (cmd).allow_routing = 0; \ - (cmd).drop_multicast = 1; \ - (cmd).trace_vlevel = 2; \ - (cmd).vpn_fd = -1; \ -} while (0); - -n2n_edge_status status; - -int start_edge(const n2n_edge_cmd_t* cmd); -int stop_edge(void); -void report_edge_status(void); - -#endif /* __ANDROID_NDK__ */ - -#endif //_EDGE_ANDROID_H_ diff --git a/android/tuntap_android.c b/android/tuntap_android.c index 14548e0..ead4ba4 100644 --- a/android/tuntap_android.c +++ b/android/tuntap_android.c @@ -15,7 +15,7 @@ * along with this program; if not, see */ -#include "../n2n.h" +#include "n2n.h" #ifdef __ANDROID_NDK__ #include @@ -57,7 +57,7 @@ int tuntap_open(tuntap_dev *device, device->ip_addr = inet_addr(device_ip); device->device_mask = inet_addr(device_mask); device->mtu = mtu; - strncpy(device->dev_name, dev, MIN(IFNAMSIZ, N2N_IFNAMSIZ)); + strncpy(device->dev_name, dev, N2N_IFNAMSIZ); return device->fd; } diff --git a/include/n2n.h b/include/n2n.h index d39471a..6014075 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -118,8 +118,8 @@ typedef struct ether_hdr ether_hdr_t; #undef N2N_HAVE_DAEMON #undef N2N_HAVE_SETUID #undef N2N_CAN_NAME_IFACE -#include "android/edge_android.h" #include +#include #define ARP_PERIOD_INTERVAL (10) /* sec */ #endif /* #ifdef __ANDROID_NDK__ */ @@ -242,13 +242,13 @@ typedef struct n2n_edge n2n_edge_t; /* Opaque, see edge_utils.c */ typedef struct sn_stats { - size_t errors; /* Number of errors encountered. */ - size_t reg_super; /* Number of REGISTER_SUPER requests received. */ - size_t reg_super_nak; /* Number of REGISTER_SUPER requests declined. */ - size_t fwd; /* Number of messages forwarded. */ - size_t broadcast; /* Number of messages broadcast to a community. */ - time_t last_fwd; /* Time when last message was forwarded. */ - time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */ + size_t errors; /* Number of errors encountered. */ + size_t reg_super; /* Number of REGISTER_SUPER requests received. */ + size_t reg_super_nak; /* Number of REGISTER_SUPER requests declined. */ + size_t fwd; /* Number of messages forwarded. */ + size_t broadcast; /* Number of messages broadcast to a community. */ + time_t last_fwd; /* Time when last message was forwarded. */ + time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */ } sn_stats_t; struct sn_community @@ -263,14 +263,14 @@ struct sn_community typedef struct n2n_sn { - time_t start_time; /* Used to measure uptime. */ - sn_stats_t stats; - int daemon; /* If non-zero then daemonise. */ - uint16_t lport; /* Local UDP port to bind to. */ - int sock; /* Main socket for UDP traffic with edges. */ - int mgmt_sock; /* management socket. */ - int lock_communities; /* If true, only loaded communities can be used. */ - struct sn_community *communities; + time_t start_time; /* Used to measure uptime. */ + sn_stats_t stats; + int daemon; /* If non-zero then daemonise. */ + uint16_t lport; /* Local UDP port to bind to. */ + int sock; /* Main socket for UDP traffic with edges. */ + int mgmt_sock; /* management socket. */ + int lock_communities; /* If true, only loaded communities can be used. */ + struct sn_community *communities; } n2n_sn_t; /* ************************************** */ @@ -311,7 +311,7 @@ void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...); /* Tuntap API */ int tuntap_open(tuntap_dev *device, char *dev, const char *address_mode, char *device_ip, - char *device_mask, const char * device_mac, int mtu); + char *device_mask, const char * device_mac, int mtu); int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len); int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len); void tuntap_close(struct tuntap_dev *tuntap); @@ -330,10 +330,10 @@ void print_edge_stats(const n2n_edge_t *eee); /* Sockets */ char* sock_to_cstr( n2n_sock_str_t out, - const n2n_sock_t * sock ); + const n2n_sock_t * sock ); SOCKET open_socket(int local_port, int bind_any); int sock_equal( const n2n_sock_t * a, - const n2n_sock_t * b ); + const n2n_sock_t * b ); /* Operations on peer_info lists. */ size_t purge_peer_list( struct peer_info ** peer_list, diff --git a/include/portable_endian.h b/include/portable_endian.h index 1b27491..9c46ffe 100644 --- a/include/portable_endian.h +++ b/include/portable_endian.h @@ -31,7 +31,7 @@ # include # include /* See http://linux.die.net/man/3/endian */ -# if defined(htobe16) && defined(htole16) && defined(be16toh) && defined(le16toh) && defined(htobe32) && defined(htole32) && defined(be32toh) && defined(htole32) && defined(htobe64) && defined(htole64) && defined(be64) && defined(le64) +# if defined(htobe16) && defined(htole16) && defined(be16toh) && defined(le16toh) && defined(htobe32) && defined(htole32) && defined(be32toh) && defined(htole32) && defined(htobe64) && defined(htole64) && defined(htobe64) && defined(be64toh) && defined(htole64) && defined(le64toh) /* Do nothing. The macros we need already exist. */ # elif !defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 9))) # include diff --git a/src/edge_utils.c b/src/edge_utils.c index ca054b2..be03405 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -28,18 +28,18 @@ static HEAP_ALLOC(wrkmem, LZO1X_1_MEM_COMPRESS); 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 check_peer_registration_needed(n2n_edge_t * eee, - uint8_t from_supernode, - const n2n_mac_t mac, - const n2n_sock_t * peer); + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer); static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port, uint8_t tos); static int edge_init_routes(n2n_edge_t *eee, n2n_route_t *routes, uint16_t num_routes); static void edge_cleanup_routes(n2n_edge_t *eee); static int supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn); static void check_known_peer_sock_change(n2n_edge_t * eee, - uint8_t from_supernode, - const n2n_mac_t mac, - const n2n_sock_t * peer, - time_t when); + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer, + time_t when); /* ************************************** */ @@ -96,6 +96,11 @@ struct n2n_edge { int multicast_joined; /**< 1 if the group has been joined.*/ #endif +#ifdef __ANDROID_NDK__ + uint32_t gateway_ip; /**< The IP address of the gateway */ + n2n_mac_t gateway_mac; /**< The MAC address of the gateway */ +#endif + /* Peers */ struct peer_info * known_peers; /**< Edges we are connected to. */ struct peer_info * pending_peers; /**< Edges we have tried to register with. */ @@ -146,16 +151,16 @@ static int is_ethMulticast(const void * buf, size_t bufsize) { /* Match 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF */ if(bufsize >= sizeof(ether_hdr_t)) { - /* copy to aligned memory */ - ether_hdr_t eh; - memcpy(&eh, buf, sizeof(ether_hdr_t)); + /* copy to aligned memory */ + ether_hdr_t eh; + memcpy(&eh, buf, sizeof(ether_hdr_t)); - if((0x01 == eh.dhost[0]) && - (0x00 == eh.dhost[1]) && - (0x5E == eh.dhost[2]) && - (0 == (0x80 & eh.dhost[3]))) - retval = 1; /* This is an ethernet multicast packet [RFC1112]. */ - } + if((0x01 == eh.dhost[0]) && + (0x00 == eh.dhost[1]) && + (0x5E == eh.dhost[2]) && + (0 == (0x80 & eh.dhost[3]))) + retval = 1; /* This is an ethernet multicast packet [RFC1112]. */ + } return retval; } @@ -169,14 +174,14 @@ static int is_ip6_discovery(const void * buf, size_t bufsize) { int retval = 0; if(bufsize >= sizeof(ether_hdr_t)) { - /* copy to aligned memory */ - ether_hdr_t eh; + /* copy to aligned memory */ + ether_hdr_t eh; - memcpy(&eh, buf, sizeof(ether_hdr_t)); + memcpy(&eh, buf, sizeof(ether_hdr_t)); - if((0x33 == eh.dhost[0]) && (0x33 == eh.dhost[1])) - retval = 1; /* This is an IPv6 multicast packet [RFC2464]. */ - } + if((0x33 == eh.dhost[0]) && (0x33 == eh.dhost[1])) + retval = 1; /* This is an IPv6 multicast packet [RFC2464]. */ + } return retval; } @@ -243,9 +248,11 @@ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *r rc = n2n_transop_cc20_init(&eee->conf, &eee->transop); break; #endif +#ifndef __ANDROID_NDK__ case N2N_TRANSFORM_ID_SPECK: rc = n2n_transop_speck_init(&eee->conf, &eee->transop); break; +#endif default: rc = n2n_transop_null_init(&eee->conf, &eee->transop); } @@ -345,49 +352,49 @@ static int supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn) { supernode_host = strtok(addr, ":"); if(supernode_host) { - in_addr_t sn_addr; - char *supernode_port = strtok(NULL, ":"); - const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL}; - struct addrinfo * ainfo = NULL; - int nameerr; + in_addr_t sn_addr; + char *supernode_port = strtok(NULL, ":"); + const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL}; + struct addrinfo * ainfo = NULL; + int nameerr; - if(supernode_port) - sn->port = atoi(supernode_port); - else - traceEvent(TRACE_WARNING, "Bad supernode parameter (-l ) %s %s:%s", - addr, supernode_host, supernode_port); + if(supernode_port) + sn->port = atoi(supernode_port); + else + traceEvent(TRACE_WARNING, "Bad supernode parameter (-l ) %s %s:%s", + addr, supernode_host, supernode_port); - nameerr = getaddrinfo(supernode_host, NULL, &aihints, &ainfo); + nameerr = getaddrinfo(supernode_host, NULL, &aihints, &ainfo); - if(0 == nameerr) - { - struct sockaddr_in * saddr; + if(0 == nameerr) + { + struct sockaddr_in * saddr; - /* ainfo s the head of a linked list if non-NULL. */ - if(ainfo && (PF_INET == ainfo->ai_family)) - { - /* It is definitely and IPv4 address -> sockaddr_in */ - saddr = (struct sockaddr_in *)ainfo->ai_addr; + /* ainfo s the head of a linked list if non-NULL. */ + if(ainfo && (PF_INET == ainfo->ai_family)) + { + /* It is definitely and IPv4 address -> sockaddr_in */ + saddr = (struct sockaddr_in *)ainfo->ai_addr; - memcpy(sn->addr.v4, &(saddr->sin_addr.s_addr), IPV4_SIZE); - sn->family=AF_INET; - } - else - { - /* Should only return IPv4 addresses due to aihints. */ - traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host); - rv = -1; - } + memcpy(sn->addr.v4, &(saddr->sin_addr.s_addr), IPV4_SIZE); + sn->family=AF_INET; + } + else + { + /* Should only return IPv4 addresses due to aihints. */ + traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host); + rv = -1; + } - freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */ - ainfo = NULL; - } else { - traceEvent(TRACE_WARNING, "Failed to resolve supernode host %s, assuming numeric", supernode_host); - sn_addr = inet_addr(supernode_host); /* uint32_t */ - memcpy(sn->addr.v4, &(sn_addr), IPV4_SIZE); - sn->family=AF_INET; - rv = -2; - } + freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */ + ainfo = NULL; + } else { + traceEvent(TRACE_WARNING, "Failed to resolve supernode host %s, assuming numeric", supernode_host); + sn_addr = inet_addr(supernode_host); /* uint32_t */ + memcpy(sn->addr.v4, &(sn_addr), IPV4_SIZE); + sn->family=AF_INET; + rv = -2; + } } else { traceEvent(TRACE_WARNING, "Wrong supernode parameter (-l )"); @@ -408,7 +415,7 @@ static void register_with_local_peers(n2n_edge_t * eee) { if(eee->multicast_joined && eee->conf.allow_p2p) { /* send registration to the local multicast group */ traceEvent(TRACE_DEBUG, "Registering with multicast group %s:%u", - N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); send_register(eee, &(eee->multicast_peer), NULL); } #else @@ -432,9 +439,9 @@ static void register_with_local_peers(n2n_edge_t * eee) { * Called from the main loop when Rx a packet for our device mac. */ static void register_with_new_peer(n2n_edge_t * eee, - uint8_t from_supernode, - const n2n_mac_t mac, - const n2n_sock_t * peer) { + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer) { /* REVISIT: purge of pending_peers not yet done. */ struct peer_info * scan; macstr_t mac_buf; @@ -462,7 +469,7 @@ static void register_with_new_peer(n2n_edge_t * eee, /* trace Sending REGISTER */ if(from_supernode) { - /* UDP NAT hole punching through supernode. Send to peer first(punch local UDP hole) + /* UDP NAT hole punching through supernode. Send to peer first(punch local UDP hole) * and then ask supernode to forward. Supernode then ask peer to ack. Some nat device * drop and block ports with incoming UDP packet if out-come traffic does not exist. * So we can alternatively set TTL so that the packet sent to peer never really reaches @@ -482,12 +489,12 @@ static void register_with_new_peer(n2n_edge_t * eee, getsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, (void *)(char *)&curTTL, &lenTTL); setsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, - (void *)(char *)&eee->conf.register_ttl, - sizeof(eee->conf.register_ttl)); + (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); + } setsockopt(eee->udp_sock, IPPROTO_IP, IP_TTL, (void *)(char *)&curTTL, sizeof(curTTL)); #endif } else { /* eee->conf.register_ttl <= 0 */ @@ -509,9 +516,9 @@ static void register_with_new_peer(n2n_edge_t * eee, /** Update the last_seen time for this peer, or get registered. */ static void check_peer_registration_needed(n2n_edge_t * eee, - uint8_t from_supernode, - const n2n_mac_t mac, - const n2n_sock_t * peer) { + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer) { struct peer_info *scan; HASH_FIND_PEER(eee->known_peers, mac, scan); @@ -540,9 +547,9 @@ static void check_peer_registration_needed(n2n_edge_t * eee, * peer must be a pointer to an element of the pending_peers list. */ static void peer_set_p2p_confirmed(n2n_edge_t * eee, - const n2n_mac_t mac, - const n2n_sock_t * peer, - time_t now) { + const n2n_mac_t mac, + const n2n_sock_t * peer, + time_t now) { struct peer_info *scan; macstr_t mac_buf; n2n_sock_str_t sockbuf; @@ -559,8 +566,8 @@ static void peer_set_p2p_confirmed(n2n_edge_t * eee, scan->last_p2p = now; traceEvent(TRACE_NORMAL, "P2P connection established: %s [%s]", - macaddr_str(mac_buf, mac), - sock_to_cstr(sockbuf, peer)); + macaddr_str(mac_buf, mac), + sock_to_cstr(sockbuf, peer)); traceEvent(TRACE_DEBUG, "=== new peer %s -> %s", macaddr_str(mac_buf, scan->mac_addr), @@ -610,14 +617,15 @@ int is_empty_ip_address(const n2n_sock_t * sock) { /* ************************************** */ static n2n_mac_t broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +static n2n_mac_t null_mac = {0, 0, 0, 0, 0, 0}; /** Check if a known peer socket has changed and possibly register again. */ static void check_known_peer_sock_change(n2n_edge_t * eee, - uint8_t from_supernode, - const n2n_mac_t mac, - const n2n_sock_t * peer, - time_t when) { + uint8_t from_supernode, + const n2n_mac_t mac, + const n2n_sock_t * peer, + time_t when) { struct peer_info *scan; n2n_sock_str_t sockbuf1; n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */ @@ -637,20 +645,20 @@ static void check_known_peer_sock_change(n2n_edge_t * eee, return; if(!sock_equal(&(scan->sock), peer)) { - if(!from_supernode) { - /* This is a P2P packet */ - traceEvent(TRACE_NORMAL, "Peer changed %s: %s -> %s", - macaddr_str(mac_buf, scan->mac_addr), - sock_to_cstr(sockbuf1, &(scan->sock)), - sock_to_cstr(sockbuf2, peer)); - /* The peer has changed public socket. It can no longer be assumed to be reachable. */ - HASH_DEL(eee->known_peers, scan); - free(scan); + if(!from_supernode) { + /* This is a P2P packet */ + traceEvent(TRACE_NORMAL, "Peer changed %s: %s -> %s", + macaddr_str(mac_buf, scan->mac_addr), + sock_to_cstr(sockbuf1, &(scan->sock)), + sock_to_cstr(sockbuf2, peer)); + /* The peer has changed public socket. It can no longer be assumed to be reachable. */ + HASH_DEL(eee->known_peers, scan); + free(scan); - register_with_new_peer(eee, from_supernode, mac, peer); - } else { - /* Don't worry about what the supernode reports, it could be seeing a different socket. */ - } + register_with_new_peer(eee, from_supernode, mac, peer); + } else { + /* Don't worry about what the supernode reports, it could be seeing a different socket. */ + } } else scan->last_seen = when; } @@ -694,14 +702,14 @@ static void check_join_multicast_group(n2n_edge_t *eee) { if(setsockopt(eee->udp_multicast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) { traceEvent(TRACE_WARNING, "Failed to bind to local multicast group %s:%u [errno %u]", - N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT, errno); + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT, errno); #ifdef WIN32 traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); #endif } else { traceEvent(TRACE_NORMAL, "Successfully joined multicast group %s:%u", - N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); + N2N_MULTICAST_GROUP, N2N_MULTICAST_PORT); eee->multicast_joined = 1; } } @@ -753,36 +761,36 @@ static void send_register_super(n2n_edge_t * eee, /** Send a QUERY_PEER packet to the current supernode. */ static void send_query_peer( n2n_edge_t * eee, const n2n_mac_t dstMac) { - uint8_t pktbuf[N2N_PKT_BUF_SIZE]; - size_t idx; - n2n_common_t cmn = {0}; - n2n_QUERY_PEER_t query = {{0}}; + uint8_t pktbuf[N2N_PKT_BUF_SIZE]; + size_t idx; + n2n_common_t cmn = {0}; + n2n_QUERY_PEER_t query = {{0}}; - cmn.ttl=N2N_DEFAULT_TTL; - cmn.pc = n2n_query_peer; - cmn.flags = 0; - memcpy( cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE ); + cmn.ttl=N2N_DEFAULT_TTL; + cmn.pc = n2n_query_peer; + cmn.flags = 0; + memcpy( cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE ); - idx=0; - encode_mac( query.srcMac, &idx, eee->device.mac_addr ); - idx=0; - encode_mac( query.targetMac, &idx, dstMac ); + idx=0; + encode_mac( query.srcMac, &idx, eee->device.mac_addr ); + idx=0; + encode_mac( query.targetMac, &idx, dstMac ); - idx=0; - encode_QUERY_PEER( pktbuf, &idx, &cmn, &query ); + idx=0; + encode_QUERY_PEER( pktbuf, &idx, &cmn, &query ); - traceEvent( TRACE_DEBUG, "send QUERY_PEER to supernode" ); + traceEvent( TRACE_DEBUG, "send QUERY_PEER to supernode" ); if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx); - sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) ); + sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) ); } /** 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_sock_t * remote_peer, + const n2n_mac_t peer_mac) { uint8_t pktbuf[N2N_PKT_BUF_SIZE]; size_t idx; /* ssize_t sent; */ @@ -895,6 +903,17 @@ static void update_supernode_reg(n2n_edge_t * eee, time_t nowTime) { traceEvent(TRACE_WARNING, "Supernode not responding, now trying %s", supernode_ip(eee)); +#ifdef __ANDROID_NDK__ + int change = 0; + pthread_mutex_lock(&g_status->mutex); + change = g_status->running_status == EDGE_STAT_SUPERNODE_DISCONNECT ? 0 : 1; + g_status->running_status = EDGE_STAT_SUPERNODE_DISCONNECT; + pthread_mutex_unlock(&g_status->mutex); + if (change) { + g_status->report_edge_status(); + } +#endif /* #ifdef __ANDROID_NDK__ */ + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; } else @@ -1000,88 +1019,101 @@ static int handle_PACKET(n2n_edge_t * eee, rx_transop_id &= (1 << (8*sizeof((uint16_t)rx_transop_id)-N2N_COMPRESSION_ID_BITLEN)) -1; if(rx_transop_id == eee->conf.transop_id) { - uint8_t is_multicast; - eth_payload = decodebuf; - eh = (ether_hdr_t*)eth_payload; - eth_size = eee->transop.rev(&eee->transop, - eth_payload, N2N_PKT_BUF_SIZE, - payload, psize, pkt->srcMac); - ++(eee->transop.rx_cnt); /* stats */ + uint8_t is_multicast; + eth_payload = decodebuf; + eh = (ether_hdr_t*)eth_payload; + eth_size = eee->transop.rev(&eee->transop, + eth_payload, N2N_PKT_BUF_SIZE, + payload, psize, pkt->srcMac); + ++(eee->transop.rx_cnt); /* stats */ - /* decompress if necessary */ - uint8_t * deflation_buffer = 0; - int32_t deflated_len; - switch (rx_compression_id) { - case N2N_COMPRESSION_ID_NONE: - break; // continue afterwards + /* decompress if necessary */ + uint8_t * deflation_buffer = 0; + int32_t deflated_len; + switch (rx_compression_id) { + case N2N_COMPRESSION_ID_NONE: + break; // continue afterwards - case N2N_COMPRESSION_ID_LZO: - deflation_buffer = malloc (N2N_PKT_BUF_SIZE); - lzo1x_decompress (eth_payload, eth_size, deflation_buffer, (lzo_uint*)&deflated_len, NULL); - break; + case N2N_COMPRESSION_ID_LZO: + deflation_buffer = malloc (N2N_PKT_BUF_SIZE); + lzo1x_decompress (eth_payload, eth_size, deflation_buffer, (lzo_uint*)&deflated_len, NULL); + break; #ifdef N2N_HAVE_ZSTD - case N2N_COMPRESSION_ID_ZSTD: - deflated_len = N2N_PKT_BUF_SIZE; - deflation_buffer = malloc (deflated_len); - deflated_len = (int32_t)ZSTD_decompress (deflation_buffer, deflated_len, eth_payload, eth_size); + case N2N_COMPRESSION_ID_ZSTD: + deflated_len = N2N_PKT_BUF_SIZE; + deflation_buffer = malloc (deflated_len); + deflated_len = (int32_t)ZSTD_decompress (deflation_buffer, deflated_len, eth_payload, eth_size); if(ZSTD_isError(deflated_len)) { - traceEvent (TRACE_ERROR, "payload decompression failed with zstd error '%s'.", - ZSTD_getErrorName(deflated_len)); - free (deflation_buffer); - return (-1); // cannot help it - } - break; + traceEvent (TRACE_ERROR, "payload decompression failed with zstd error '%s'.", + ZSTD_getErrorName(deflated_len)); + free (deflation_buffer); + return (-1); // cannot help it + } + break; #endif - default: - traceEvent (TRACE_ERROR, "payload decompression failed: received packet indicating unsupported %s compression.", - compression_str(rx_compression_id)); - return (-1); // cannot handle it - } + default: + traceEvent (TRACE_ERROR, "payload decompression failed: received packet indicating unsupported %s compression.", + compression_str(rx_compression_id)); + return (-1); // cannot handle it + } if(rx_compression_id) { - traceEvent (TRACE_DEBUG, "payload decompression [%s]: deflated %u bytes to %u bytes", - compression_str(rx_compression_id), eth_size, (int)deflated_len); - memcpy(eth_payload ,deflation_buffer, deflated_len ); - eth_size = deflated_len; - free (deflation_buffer); - } + traceEvent (TRACE_DEBUG, "payload decompression [%s]: deflated %u bytes to %u bytes", + compression_str(rx_compression_id), eth_size, (int)deflated_len); + memcpy(eth_payload ,deflation_buffer, deflated_len ); + eth_size = deflated_len; + free (deflation_buffer); + } - is_multicast = (is_ip6_discovery(eth_payload, eth_size) || is_ethMulticast(eth_payload, eth_size)); + is_multicast = (is_ip6_discovery(eth_payload, eth_size) || is_ethMulticast(eth_payload, eth_size)); - if(eee->conf.drop_multicast && is_multicast) { - traceEvent(TRACE_INFO, "Dropping RX multicast"); - return(-1); - } else if((!eee->conf.allow_routing) && (!is_multicast)) { - /* Check if it is a routed packet */ - if((ntohs(eh->type) == 0x0800) && (eth_size >= ETH_FRAMESIZE + IP4_MIN_SIZE)) { - uint32_t *dst = (uint32_t*)ð_payload[ETH_FRAMESIZE + IP4_DSTOFFSET]; - u_int8_t *dst_mac = (u_int8_t*)eth_payload; + if(eee->conf.drop_multicast && is_multicast) { + traceEvent(TRACE_INFO, "Dropping RX multicast"); + return(-1); + } else if((!eee->conf.allow_routing) && (!is_multicast)) { + /* Check if it is a routed packet */ + if((ntohs(eh->type) == 0x0800) && (eth_size >= ETH_FRAMESIZE + IP4_MIN_SIZE)) { + uint32_t *dst = (uint32_t*)ð_payload[ETH_FRAMESIZE + IP4_DSTOFFSET]; + u_int8_t *dst_mac = (u_int8_t*)eth_payload; - /* Note: all elements of the_ip are in network order */ - if(!memcmp(dst_mac, broadcast_mac, 6)) - traceEvent(TRACE_DEBUG, "Broadcast packet [%s]", - intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); - else if((*dst != eee->device.ip_addr)) { - /* This is a packet that needs to be routed */ - traceEvent(TRACE_INFO, "Discarding routed packet [%s]", - intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); - return(-1); - } else { - /* This packet is directed to us */ - /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ + /* Note: all elements of the_ip are in network order */ + if(!memcmp(dst_mac, broadcast_mac, 6)) + traceEvent(TRACE_DEBUG, "Broadcast packet [%s]", + intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); + else if((*dst != eee->device.ip_addr)) { + /* This is a packet that needs to be routed */ + traceEvent(TRACE_INFO, "Discarding routed packet [%s]", + intoa(ntohl(*dst), ip_buf, sizeof(ip_buf))); + return(-1); + } else { + /* This packet is directed to us */ + /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */ + } } } - } - /* Write ethernet packet to tap device. */ - traceEvent(TRACE_DEBUG, "sending to TAP %u", (unsigned int)eth_size); - data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size); +#ifdef __ANDROID_NDK__ + if((psize >= 36) && + (ntohs(*((uint16_t*)ð_payload[12])) == 0x0806) && /* ARP */ + (ntohs(*((uint16_t*)ð_payload[20])) == 0x0002) && /* REPLY */ + (!memcmp(ð_payload[28], &eee->gateway_ip, 4))) { /* From gateway */ + memcpy(eee->gateway_mac, ð_payload[22], 6); + + traceEvent(TRACE_INFO, "Gateway MAC: %02X:%02X:%02X:%02X:%02X:%02X", + eee->gateway_mac[0], eee->gateway_mac[1], eee->gateway_mac[2], + eee->gateway_mac[3], eee->gateway_mac[4], eee->gateway_mac[5]); + } +#endif + + /* Write ethernet packet to tap device. */ + traceEvent(TRACE_DEBUG, "sending to TAP %u", (unsigned int)eth_size); + data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size); if(data_sent_len == eth_size) - { - retval = 0; - } - } + { + retval = 0; + } + } else { traceEvent(TRACE_ERROR, "invalid transop ID: expected %s(%u), got %s(%u)", @@ -1296,8 +1328,8 @@ static int find_peer_destination(n2n_edge_t * eee, if(retval == 0) { memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in)); traceEvent(TRACE_DEBUG, "P2P Peer [MAC=%02X:%02X:%02X:%02X:%02X:%02X] not found, using supernode", - mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF, - mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF); + mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF, + mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF); check_query_peer_info(eee, now, mac_address); } @@ -1337,8 +1369,8 @@ static int send_packet(n2n_edge_t * eee, } traceEvent(TRACE_INFO, "Tx PACKET to %s (dest=%s) [%u B]", - sock_to_cstr(sockbuf, &destination), - macaddr_str(mac_buf, dstMac), pktlen); + sock_to_cstr(sockbuf, &destination), + macaddr_str(mac_buf, dstMac), pktlen); /* s = */ sendto_sock(eee->udp_sock, pktbuf, pktlen, &destination); @@ -1349,7 +1381,7 @@ static int send_packet(n2n_edge_t * eee, /** A layer-2 packet was received at the tunnel and needs to be sent via UDP. */ static void send_packet2net(n2n_edge_t * eee, - uint8_t *tap_pkt, size_t len) { + uint8_t *tap_pkt, size_t len) { ipstr_t ip_buf; n2n_mac_t destMac; @@ -1362,6 +1394,13 @@ static void send_packet2net(n2n_edge_t * eee, ether_hdr_t eh; +#ifdef __ANDROID_NDK__ + if(!memcmp(tap_pkt, null_mac, 6)) { + traceEvent(TRACE_DEBUG, "Detected packet for the gateway"); + memcpy(tap_pkt, eee->gateway_mac, 6); + } +#endif + /* tap_pkt is not aligned so we have to copy to aligned memory */ memcpy(&eh, tap_pkt, sizeof(ether_hdr_t)); @@ -1411,38 +1450,38 @@ static void send_packet2net(n2n_edge_t * eee, int32_t compression_len; switch (eee->conf.compression) { - case N2N_COMPRESSION_ID_LZO: - compression_buffer = malloc (len + len / 16 + 64 + 3); + case N2N_COMPRESSION_ID_LZO: + compression_buffer = malloc (len + len / 16 + 64 + 3); if(lzo1x_1_compress(tap_pkt, len, compression_buffer, (lzo_uint*)&compression_len, wrkmem) == LZO_E_OK) { if(compression_len < len) { - pkt.compression = N2N_COMPRESSION_ID_LZO; - } - } - break; + pkt.compression = N2N_COMPRESSION_ID_LZO; + } + } + break; #ifdef N2N_HAVE_ZSTD - case N2N_COMPRESSION_ID_ZSTD: - compression_len = N2N_PKT_BUF_SIZE + 128; - compression_buffer = malloc (compression_len); // leaves enough room, for exact size call compression_len = ZSTD_compressBound (len); (slower) - compression_len = (int32_t)ZSTD_compress(compression_buffer, compression_len, tap_pkt, len, ZSTD_COMPRESSION_LEVEL) ; + case N2N_COMPRESSION_ID_ZSTD: + compression_len = N2N_PKT_BUF_SIZE + 128; + compression_buffer = malloc (compression_len); // leaves enough room, for exact size call compression_len = ZSTD_compressBound (len); (slower) + compression_len = (int32_t)ZSTD_compress(compression_buffer, compression_len, tap_pkt, len, ZSTD_COMPRESSION_LEVEL) ; if(!ZSTD_isError(compression_len)) { if(compression_len < len) { - pkt.compression = N2N_COMPRESSION_ID_ZSTD; - } - } else { - traceEvent (TRACE_ERROR, "payload compression failed with zstd error '%s'.", - ZSTD_getErrorName(compression_len)); - free (compression_buffer); - // continue with unset without pkt.compression --> will send uncompressed - } - break; + pkt.compression = N2N_COMPRESSION_ID_ZSTD; + } + } else { + traceEvent (TRACE_ERROR, "payload compression failed with zstd error '%s'.", + ZSTD_getErrorName(compression_len)); + free (compression_buffer); + // continue with unset without pkt.compression --> will send uncompressed + } + break; #endif - default: - break; + default: + break; } if(pkt.compression) { traceEvent (TRACE_DEBUG, "payload compression [%s]: compressed %u bytes to %u bytes\n", - compression_str(pkt.compression), len, compression_len); + compression_str(pkt.compression), len, compression_len); memcpy (tap_pkt, compression_buffer, compression_len); len = compression_len; @@ -1463,11 +1502,11 @@ static void send_packet2net(n2n_edge_t * eee, packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx); idx += eee->transop.fwd(&eee->transop, - pktbuf+idx, N2N_PKT_BUF_SIZE-idx, - tap_pkt, len, pkt.dstMac); + pktbuf+idx, N2N_PKT_BUF_SIZE-idx, + tap_pkt, len, pkt.dstMac); traceEvent(TRACE_DEBUG, "Encode %u B PACKET [%u B data, %u B overhead] transform %u", - (u_int)idx, (u_int)len, (u_int)(idx-len), tx_transop_idx); + (u_int)idx, (u_int)len, (u_int)(idx-len), tx_transop_idx); #ifdef MTU_ASSERT_VALUE { @@ -1501,15 +1540,15 @@ static void readFromTAPSocket(n2n_edge_t * eee) { 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__ */ if((len <= 0) || (len > N2N_PKT_BUF_SIZE)) { traceEvent(TRACE_WARNING, "read()=%d [%d/%s]", - (signed int)len, errno, strerror(errno)); + (signed int)len, errno, strerror(errno)); } else { @@ -1534,6 +1573,57 @@ static void readFromTAPSocket(n2n_edge_t * eee) { /* ************************************** */ +#ifdef __ANDROID_NDK__ + +static char arp_packet[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Dest mac */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */ + 0x08, 0x06, /* ARP */ + 0x00, 0x01, /* Ethernet */ + 0x08, 0x00, /* IP */ + 0x06, /* Hw Size */ + 0x04, /* Protocol Size */ + 0x00, 0x01, /* ARP Request */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */ + 0x00, 0x00, 0x00, 0x00, /* Src IP */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Target mac */ + 0x00, 0x00, 0x00, 0x00 /* Target IP */ +}; + +/* ************************************** */ + +static int build_unicast_arp(char *buffer, size_t buffer_len, uint32_t target, tuntap_dev *device) { + if(buffer_len < sizeof(arp_packet)) return(-1); + + memcpy(buffer, arp_packet, sizeof(arp_packet)); + memcpy(&buffer[6], device->mac_addr, 6); + memcpy(&buffer[22], device->mac_addr, 6); + memcpy(&buffer[28], &device->ip_addr, 4); + memcpy(&buffer[32], broadcast_mac, 6); + memcpy(&buffer[38], &target, 4); + return(sizeof(arp_packet)); +} + +/* ************************************** */ + +/** Called periodically to update the gateway MAC address. The ARP reply packet + is handled in handle_PACKET . */ + +static void update_gateway_mac(n2n_edge_t *eee) { + if(eee->gateway_ip != 0) { + size_t len; + char buffer[48]; + + len = build_unicast_arp(buffer, sizeof(buffer), eee->gateway_ip, &eee->device); + traceEvent(TRACE_DEBUG, "Updating gateway mac"); + send_packet2net(eee, (uint8_t*)buffer, len); + } +} + +#endif + +/* ************************************** */ + /** Read a datagram from the main UDP socket to the internet. */ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { n2n_common_t cmn; /* common fields in the packet header */ @@ -1564,12 +1654,12 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { #ifdef WIN32 if(WSAGetLastError() != WSAECONNRESET) #endif - { - traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", recvlen, errno, strerror(errno)); + { + traceEvent(TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", recvlen, errno, strerror(errno)); #ifdef WIN32 - traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); + traceEvent(TRACE_ERROR, "WSAGetLastError(): %u", WSAGetLastError()); #endif - } + } return; /* failed to receive data from UDP */ } @@ -1609,174 +1699,187 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE; if(0 == memcmp(cmn.community, eee->conf.community_name, N2N_COMMUNITY_SIZE)) { - switch(msg_type) { - case MSG_TYPE_PACKET: + switch(msg_type) { + case MSG_TYPE_PACKET: { - /* process PACKET - most frequent so first in list. */ - n2n_PACKET_t pkt; + /* process PACKET - most frequent so first in list. */ + n2n_PACKET_t pkt; - decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); + decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); - if(is_valid_peer_sock(&pkt.sock)) - orig_sender = &(pkt.sock); + if(is_valid_peer_sock(&pkt.sock)) + orig_sender = &(pkt.sock); - if(!from_supernode) { - /* This is a P2P packet from the peer. We purge a pending - * registration towards the possibly nat-ted peer address as we now have - * a valid channel. We still use check_peer_registration_needed in - * handle_PACKET to double check this. - */ - traceEvent(TRACE_DEBUG, "Got P2P packet"); - find_and_remove_peer(&eee->pending_peers, pkt.srcMac); - } - - traceEvent(TRACE_INFO, "Rx PACKET from %s (sender=%s) [%u B]", - sock_to_cstr(sockbuf1, &sender), - sock_to_cstr(sockbuf2, orig_sender), - recvlen); - - handle_PACKET(eee, &cmn, &pkt, orig_sender, udp_buf+idx, recvlen-idx); - break; - } - case MSG_TYPE_REGISTER: - { - /* Another edge is registering with us */ - n2n_REGISTER_t reg; - n2n_mac_t null_mac = { '\0' }; - int via_multicast; - - decode_REGISTER(®, &cmn, udp_buf, &rem, &idx); - - if(is_valid_peer_sock(®.sock)) - orig_sender = &(reg.sock); - - via_multicast = !memcmp(reg.dstMac, null_mac, 6); - - if(via_multicast && !memcmp(reg.srcMac, eee->device.mac_addr, 6)) { - traceEvent(TRACE_DEBUG, "Skipping REGISTER from self"); - break; - } - - if(!via_multicast && memcmp(reg.dstMac, eee->device.mac_addr, 6)) { - traceEvent(TRACE_DEBUG, "Skipping REGISTER for other peer"); - break; - } - - if(!from_supernode) { - /* This is a P2P registration from the peer. We purge a pending - * registration towards the possibly nat-ted peer address as we now have - * a valid channel. We still use check_peer_registration_needed below - * to double check this. - */ - traceEvent(TRACE_DEBUG, "Got P2P register"); - find_and_remove_peer(&eee->pending_peers, reg.srcMac); - - /* NOTE: only ACK to peers */ - send_register_ack(eee, orig_sender, ®); - } - - traceEvent(TRACE_INFO, "Rx REGISTER src=%s dst=%s from peer %s (%s)", - macaddr_str(mac_buf1, reg.srcMac), - macaddr_str(mac_buf2, reg.dstMac), - sock_to_cstr(sockbuf1, &sender), - sock_to_cstr(sockbuf2, orig_sender)); - - check_peer_registration_needed(eee, from_supernode, reg.srcMac, orig_sender); - break; - } - case MSG_TYPE_REGISTER_ACK: - { - /* Peer edge is acknowledging our register request */ - n2n_REGISTER_ACK_t ra; - - decode_REGISTER_ACK(&ra, &cmn, udp_buf, &rem, &idx); - - if(is_valid_peer_sock(&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), - macaddr_str(mac_buf2, ra.dstMac), - sock_to_cstr(sockbuf1, &sender), - sock_to_cstr(sockbuf2, orig_sender)); - - peer_set_p2p_confirmed(eee, ra.srcMac, &sender, now); - break; - } - case MSG_TYPE_REGISTER_SUPER_ACK: - { - n2n_REGISTER_SUPER_ACK_t ra; - - if(eee->sn_wait) - { - decode_REGISTER_SUPER_ACK(&ra, &cmn, udp_buf, &rem, &idx); - - if(is_valid_peer_sock(&ra.sock)) - orig_sender = &(ra.sock); - - traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s). Attempts %u", - macaddr_str(mac_buf1, ra.edgeMac), - sock_to_cstr(sockbuf1, &sender), - sock_to_cstr(sockbuf2, orig_sender), - (unsigned int)eee->sup_attempts); - - if(0 == memcmp(ra.cookie, eee->last_cookie, N2N_COOKIE_SIZE)) - { - if(ra.num_sn > 0) - { - traceEvent(TRACE_NORMAL, "Rx REGISTER_SUPER_ACK backup supernode at %s", - sock_to_cstr(sockbuf1, &(ra.sn_bak))); - } - - eee->last_sup = now; - eee->sn_wait=0; - eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */ - - /* NOTE: the register_interval should be chosen by the edge node - * based on its NAT configuration. */ - //eee->conf.register_interval = ra.lifetime; - } - else - { - traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old cookie."); - } + if(!from_supernode) { + /* This is a P2P packet from the peer. We purge a pending + * registration towards the possibly nat-ted peer address as we now have + * a valid channel. We still use check_peer_registration_needed in + * handle_PACKET to double check this. + */ + traceEvent(TRACE_DEBUG, "Got P2P packet"); + find_and_remove_peer(&eee->pending_peers, pkt.srcMac); } - else - { - traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with no outstanding REGISTER_SUPER."); - } - break; - } case MSG_TYPE_PEER_INFO: { - n2n_PEER_INFO_t pi; - struct peer_info * scan; - decode_PEER_INFO( &pi, &cmn, udp_buf, &rem, &idx ); - if(!is_valid_peer_sock(&pi.sock)) { - traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]", - sock_to_cstr(sockbuf1, &pi.sock), - macaddr_str(mac_buf1, pi.mac) ); + traceEvent(TRACE_INFO, "Rx PACKET from %s (sender=%s) [%u B]", + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender), + recvlen); + + handle_PACKET(eee, &cmn, &pkt, orig_sender, udp_buf+idx, recvlen-idx); + break; + } + case MSG_TYPE_REGISTER: + { + /* Another edge is registering with us */ + n2n_REGISTER_t reg; + n2n_mac_t null_mac = { '\0' }; + int via_multicast; + + decode_REGISTER(®, &cmn, udp_buf, &rem, &idx); + + if(is_valid_peer_sock(®.sock)) + orig_sender = &(reg.sock); + + via_multicast = !memcmp(reg.dstMac, null_mac, 6); + + if(via_multicast && !memcmp(reg.srcMac, eee->device.mac_addr, 6)) { + traceEvent(TRACE_DEBUG, "Skipping REGISTER from self"); break; } - HASH_FIND_PEER(eee->pending_peers, pi.mac, scan); + if(!via_multicast && memcmp(reg.dstMac, eee->device.mac_addr, 6)) { + traceEvent(TRACE_DEBUG, "Skipping REGISTER for other peer"); + break; + } + + if(!from_supernode) { + /* This is a P2P registration from the peer. We purge a pending + * registration towards the possibly nat-ted peer address as we now have + * a valid channel. We still use check_peer_registration_needed below + * to double check this. + */ + traceEvent(TRACE_DEBUG, "Got P2P register"); + find_and_remove_peer(&eee->pending_peers, reg.srcMac); + + /* NOTE: only ACK to peers */ + send_register_ack(eee, orig_sender, ®); + } + + traceEvent(TRACE_INFO, "Rx REGISTER src=%s dst=%s from peer %s (%s)", + macaddr_str(mac_buf1, reg.srcMac), + macaddr_str(mac_buf2, reg.dstMac), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender)); + + check_peer_registration_needed(eee, from_supernode, reg.srcMac, orig_sender); + break; + } + case MSG_TYPE_REGISTER_ACK: + { + /* Peer edge is acknowledging our register request */ + n2n_REGISTER_ACK_t ra; + + decode_REGISTER_ACK(&ra, &cmn, udp_buf, &rem, &idx); + + if(is_valid_peer_sock(&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), + macaddr_str(mac_buf2, ra.dstMac), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender)); + + peer_set_p2p_confirmed(eee, ra.srcMac, &sender, now); + break; + } + case MSG_TYPE_REGISTER_SUPER_ACK: + { + n2n_REGISTER_SUPER_ACK_t ra; + + if(eee->sn_wait) + { + decode_REGISTER_SUPER_ACK(&ra, &cmn, udp_buf, &rem, &idx); + + if(is_valid_peer_sock(&ra.sock)) + orig_sender = &(ra.sock); + + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s). Attempts %u", + macaddr_str(mac_buf1, ra.edgeMac), + sock_to_cstr(sockbuf1, &sender), + sock_to_cstr(sockbuf2, orig_sender), + (unsigned int)eee->sup_attempts); + + if(0 == memcmp(ra.cookie, eee->last_cookie, N2N_COOKIE_SIZE)) + { + if(ra.num_sn > 0) + { + traceEvent(TRACE_NORMAL, "Rx REGISTER_SUPER_ACK backup supernode at %s", + sock_to_cstr(sockbuf1, &(ra.sn_bak))); + } + + eee->last_sup = now; + eee->sn_wait=0; + eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */ + +#ifdef __ANDROID_NDK__ + int change = 0; + pthread_mutex_lock(&g_status->mutex); + change = g_status->running_status == EDGE_STAT_CONNECTED ? 0 : 1; + g_status->running_status = EDGE_STAT_CONNECTED; + pthread_mutex_unlock(&g_status->mutex); + if (change) { + g_status->report_edge_status(); + } + + update_gateway_mac(eee); +#endif /* #ifdef __ANDROID_NDK__ */ + + /* NOTE: the register_interval should be chosen by the edge node + * based on its NAT configuration. */ + //eee->conf.register_interval = ra.lifetime; + } + else + { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old cookie."); + } + } + else + { + traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with no outstanding REGISTER_SUPER."); + } + break; + } case MSG_TYPE_PEER_INFO: { + n2n_PEER_INFO_t pi; + struct peer_info * scan; + decode_PEER_INFO( &pi, &cmn, udp_buf, &rem, &idx ); + + if(!is_valid_peer_sock(&pi.sock)) { + traceEvent(TRACE_DEBUG, "Skip invalid PEER_INFO %s [%s]", + sock_to_cstr(sockbuf1, &pi.sock), + macaddr_str(mac_buf1, pi.mac) ); + break; + } + + HASH_FIND_PEER(eee->pending_peers, pi.mac, scan); if(scan) { scan->sock = pi.sock; traceEvent(TRACE_INFO, "Rx PEER_INFO for %s: is at %s", macaddr_str(mac_buf1, pi.mac), sock_to_cstr(sockbuf1, &pi.sock)); send_register(eee, &scan->sock, scan->mac_addr); - } else { + } else { traceEvent(TRACE_INFO, "Rx PEER_INFO unknown peer %s", macaddr_str(mac_buf1, pi.mac) ); - } + } - break; - } - default: - /* Not a known message type */ - traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type); - return; - } /* switch(msg_type) */ + break; + } + default: + /* Not a known message type */ + traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type); + return; + } /* switch(msg_type) */ } else if(from_supernode) /* if(community match) */ traceEvent(TRACE_WARNING, "Received packet with unknown community"); else @@ -1871,10 +1974,10 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { #ifndef SKIP_MULTICAST_PEERS_DISCOVERY 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_DEBUG, "Received packet from multicast socket"); - readFromIPSocket(eee, eee->udp_multicast_sock); + /* Read a cooked socket from the internet socket (multicast). Writes on the TAP + * socket. */ + traceEvent(TRACE_DEBUG, "Received packet from multicast socket"); + readFromIPSocket(eee, eee->udp_multicast_sock); } #endif @@ -1907,7 +2010,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { numPurged += purge_expired_registrations(&eee->pending_peers, &last_purge_pending); if(numPurged > 0) { - traceEvent(TRACE_INFO, "%u peers removed. now: pending=%u, operational=%u", + traceEvent(TRACE_INFO, "%u peers removed. now: pending=%u, operational=%u", numPurged, HASH_COUNT(eee->pending_peers), HASH_COUNT(eee->known_peers)); @@ -1993,7 +2096,7 @@ static int edge_init_sockets(n2n_edge_t *eee, int udp_local_port, int mgmt_port, if(setsockopt(eee->udp_sock, IPPROTO_IP, IP_MTU_DISCOVER, &sockopt, sizeof(sockopt)) < 0) traceEvent(TRACE_WARNING, "Could not %s PMTU discovery[%d]: %s", - (eee->conf.disable_pmtu_discovery) ? "disable" : "enable", errno, strerror(errno)); + (eee->conf.disable_pmtu_discovery) ? "disable" : "enable", errno, strerror(errno)); else traceEvent(TRACE_DEBUG, "PMTU discovery %s", (eee->conf.disable_pmtu_discovery) ? "disabled" : "enabled"); #endif @@ -2073,14 +2176,14 @@ static char* route_cmd_to_str(int cmd, const n2n_route_t *route, char *buf, size char netbuf[64], gwbuf[64]; switch(cmd) { - case RTM_NEWROUTE: - cmd_str = "Add"; - break; - case RTM_DELROUTE: - cmd_str = "Delete"; - break; - default: - cmd_str = "?"; + case RTM_NEWROUTE: + cmd_str = "Add"; + break; + case RTM_DELROUTE: + cmd_str = "Delete"; + break; + default: + cmd_str = "?"; } addr.s_addr = route->net_addr; @@ -2094,30 +2197,30 @@ static char* route_cmd_to_str(int cmd, const n2n_route_t *route, char *buf, size } /* Adapted from https://olegkutkov.me/2019/08/29/modifying-linux-network-routes-using-netlink/ */ -#define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) /* Add new data to rtattr */ static int rtattr_add(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen) { - int len = RTA_LENGTH(alen); - struct rtattr *rta; + int len = RTA_LENGTH(alen); + struct rtattr *rta; - if(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { - traceEvent(TRACE_ERROR, "rtattr_add error: message exceeded bound of %d\n", maxlen); - return -1; - } + if(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + traceEvent(TRACE_ERROR, "rtattr_add error: message exceeded bound of %d\n", maxlen); + return -1; + } - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = len; + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; - if(alen) - memcpy(RTA_DATA(rta), data, alen); + if(alen) + memcpy(RTA_DATA(rta), data, alen); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); - return 0; + return 0; } static int routectl(int cmd, int flags, n2n_route_t *route, int if_idx) { @@ -2452,3 +2555,9 @@ int quick_edge_init(char *device_name, char *community_name, tuntap_close(&tuntap); return(rv); } + +/* ************************************** */ + +#ifdef __ANDROID_NDK__ +#include "../android/edge_android.c" +#endif diff --git a/src/n2n.c b/src/n2n.c index fe8d39a..8e574a7 100644 --- a/src/n2n.c +++ b/src/n2n.c @@ -22,6 +22,10 @@ #include +#ifdef __ANDROID_NDK__ +#include +#endif + #define PURGE_REGISTRATION_FREQUENCY 30 #define REGISTRATION_TIMEOUT 60 @@ -31,6 +35,47 @@ static const uint8_t ipv6_multicast_addr[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x /* ************************************** */ +#ifdef __ANDROID_NDK__ + +static int protect_socket(int sock) { + JNIEnv *env = NULL; + + if(!g_status) + return(-1); + + if ((*g_status->jvm)->GetEnv(g_status->jvm, &env, JNI_VERSION_1_1) != JNI_OK || !env) { + traceEvent(TRACE_ERROR, "GetEnv failed"); + return(-1); + } + + jclass vpn_service_cls = (*env)->GetObjectClass(env, g_status->jobj_service); + + if(!vpn_service_cls) { + traceEvent(TRACE_ERROR, "GetObjectClass(VpnService) failed"); + return(-1); + } + + /* Call VpnService protect */ + jmethodID midProtect = (*env)->GetMethodID(env, vpn_service_cls, "protect", "(I)Z"); + if(!midProtect) { + traceEvent(TRACE_ERROR, "Could not resolve VpnService::protect"); + return(-1); + } + + jboolean isProtected = (*env)->CallBooleanMethod(env, g_status->jobj_service, midProtect, sock); + + if(!isProtected) { + traceEvent(TRACE_ERROR, "VpnService::protect failed"); + return(-1); + } + + return(0); +} + +#endif + +/* ************************************** */ + SOCKET open_socket(int local_port, int bind_any) { SOCKET sock_fd; struct sockaddr_in local_address; @@ -59,6 +104,11 @@ SOCKET open_socket(int local_port, int bind_any) { return(-1); } +#ifdef __ANDROID_NDK__ + /* Protect the socket so that the supernode traffic won't go inside the n2n VPN */ + protect_socket(sock_fd); +#endif + return(sock_fd); }