From 346631ffe8267292e6feed0e595316cbb730bfc6 Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Tue, 30 Jun 2020 13:01:37 +0200 Subject: [PATCH] Add the callbacks API Callbacks allow n2n API users to extend n2n without modifying the upstream code. This also allows us to move the hin2n code, which is specific of android, out of the n2n repository. --- include/n2n.h | 37 +++++++++++++++- src/edge_utils.c | 112 ++++++++++++++++++++--------------------------- 2 files changed, 83 insertions(+), 66 deletions(-) diff --git a/include/n2n.h b/include/n2n.h index 6014075..e5de4e8 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -215,6 +215,36 @@ typedef struct n2n_route { in_addr_t gateway; } n2n_route_t; +typedef struct n2n_edge n2n_edge_t; /* Opaque, see edge_utils.c */ + +/* *************************************************** */ + +typedef enum { + N2N_ACCEPT = 0, + N2N_DROP = 1 +} n2n_verdict; + +/* *************************************************** */ + +/* Callbacks allow external programs to attach functions in response to + * N2N events. */ +typedef struct n2n_edge_callbacks { + /* The supernode registration has been updated */ + void (*sn_registration_updated)(n2n_edge_t *eee, time_t now, const n2n_sock_t *sn); + + /* A packet has been received from a peer. N2N_DROP can be returned to + * drop the packet. The packet payload can be modified. */ + n2n_verdict (*packet_from_peer)(n2n_edge_t *eee, const n2n_sock_t *peer, uint8_t *payload, uint16_t payload_size); + + /* A packet has been received from the TAP interface. N2N_DROP can be + * returned to drop the packet. The packet payload can be modified. */ + n2n_verdict (*packet_from_tap)(n2n_edge_t *eee, uint8_t *payload, uint16_t payload_size); + + void (*ip_address_changed)(n2n_edge_t *eee, uint32_t old_ip, uint32_t new_ip); +} n2n_edge_callbacks_t; + +/* *************************************************** */ + typedef struct n2n_edge_conf { n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES]; n2n_route_t *routes; /**< Networks to route through n2n */ @@ -238,8 +268,6 @@ typedef struct n2n_edge_conf { int mgmt_port; } n2n_edge_conf_t; -typedef struct n2n_edge n2n_edge_t; /* Opaque, see edge_utils.c */ - typedef struct sn_stats { size_t errors; /* Number of errors encountered. */ @@ -351,6 +379,11 @@ void edge_term_conf(n2n_edge_conf_t *conf); /* Public functions */ n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv); void edge_term(n2n_edge_t *eee); +void edge_set_callbacks(n2n_edge_t *eee, const n2n_edge_callbacks_t *callbacks); +void edge_set_userdata(n2n_edge_t *eee, void *user_data); +void* edge_get_userdata(n2n_edge_t *eee); +void edge_send_packet2net(n2n_edge_t *eee, uint8_t *tap_pkt, size_t len); +void edge_read_from_tap(n2n_edge_t *eee); int run_edge_loop(n2n_edge_t *eee, int *keep_running); int quick_edge_init(char *device_name, char *community_name, char *encrypt_key, char *device_mac, diff --git a/src/edge_utils.c b/src/edge_utils.c index a2b08ab..982dee2 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -43,12 +43,6 @@ static void check_known_peer_sock_change(n2n_edge_t * eee, /* ************************************** */ -#ifdef __ANDROID_NDK__ -#include "../android/edge_android.c" -#endif - -/* ************************************** */ - int edge_verify_conf(const n2n_edge_conf_t *conf) { if(conf->community_name[0] == 0) return(-1); @@ -89,7 +83,9 @@ struct n2n_edge { tuntap_dev device; /**< All about the TUNTAP device */ n2n_trans_op_t transop; /**< The transop to use when encoding */ n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */ - n2n_route_t *sn_route_to_clean; /**< Supernode route to clean */ + n2n_route_t *sn_route_to_clean; /**< Supernode route to clean */ + n2n_edge_callbacks_t cb; /**< API callbacks */ + void *user_data; /**< Can hold user data */ /* Sockets */ n2n_sock_t supernode; @@ -102,11 +98,6 @@ 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. */ @@ -123,6 +114,24 @@ struct n2n_edge { /* ************************************** */ +void edge_set_callbacks(n2n_edge_t *eee, const n2n_edge_callbacks_t *callbacks) { + memcpy(&eee->cb, callbacks, sizeof(n2n_edge_callbacks_t)); +} + +/* ************************************** */ + +void edge_set_userdata(n2n_edge_t *eee, void *user_data) { + eee->user_data = user_data; +} + +/* ************************************** */ + +void* edge_get_userdata(n2n_edge_t *eee) { + return(eee->user_data); +} + +/* ************************************** */ + const char* transop_str(enum n2n_transform tr) { switch(tr) { case N2N_TRANSFORM_ID_NULL: return("null"); @@ -254,11 +263,9 @@ 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); } @@ -909,17 +916,6 @@ 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 @@ -1098,18 +1094,13 @@ static int handle_PACKET(n2n_edge_t * eee, } } -#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); + if(eee->cb.packet_from_peer) { + if(eee->cb.packet_from_peer(eee, orig_sender, eth_payload, eth_size) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)eth_size); - 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 + return(0); + } + } /* Write ethernet packet to tap device. */ traceEvent(TRACE_DEBUG, "sending to TAP %u", (unsigned int)eth_size); @@ -1386,7 +1377,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, +void edge_send_packet2net(n2n_edge_t * eee, uint8_t *tap_pkt, size_t len) { ipstr_t ip_buf; n2n_mac_t destMac; @@ -1400,13 +1391,6 @@ 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)); @@ -1533,7 +1517,7 @@ static void send_packet2net(n2n_edge_t * eee, /** Read a single packet from the TAP interface, process it and write out the * corresponding packet to the cooked socket. */ -static void readFromTAPSocket(n2n_edge_t * eee) { +void edge_read_from_tap(n2n_edge_t * eee) { /* tun -> remote */ uint8_t eth_pkt[N2N_PKT_BUF_SIZE]; macstr_t mac_buf; @@ -1572,7 +1556,15 @@ static void readFromTAPSocket(n2n_edge_t * eee) { } else { - send_packet2net(eee, eth_pkt, len); + if(eee->cb.packet_from_tap) { + if(eee->cb.packet_from_tap(eee, eth_pkt, len) == N2N_DROP) { + traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)len); + + return; + } + } + + edge_send_packet2net(eee, eth_pkt, len); } } } @@ -1690,7 +1682,6 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { { /* 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); @@ -1780,20 +1771,8 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { eee->sn_wait=0; eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */ -#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__ */ + if(eee->cb.sn_registration_updated) + eee->cb.sn_registration_updated(eee, now, &sender); /* NOTE: the register_interval should be chosen by the edge node * based on its NAT configuration. */ @@ -1886,7 +1865,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { * * select() is used to wait for input on either the TAP fd or the UDP/TCP * socket. When input is present the data is read and processed by either - * readFromIPSocket() or readFromTAPSocket() + * readFromIPSocket() or edge_read_from_tap() */ while(*keep_running) { @@ -1943,7 +1922,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { #ifdef __ANDROID_NDK__ if(uip_arp_len != 0) { - readFromTAPSocket(eee); + edge_read_from_tap(eee); uip_arp_len = 0; } #endif /* #ifdef __ANDROID_NDK__ */ @@ -1958,7 +1937,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { if(FD_ISSET(eee->device.fd, &socket_mask)) { /* Read an ethernet frame from the TAP socket. Write on the IP * socket. */ - readFromTAPSocket(eee); + edge_read_from_tap(eee); } #endif } @@ -1978,9 +1957,14 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) { if(eee->conf.dyn_ip_mode && ((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) { + uint32_t old_ip = eee->device.ip_addr; + traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address."); tuntap_get_address(&(eee->device)); lastIfaceCheck = nowTime; + + if((old_ip != eee->device.ip_addr) && eee->cb.ip_address_changed) + eee->cb.ip_address_changed(eee, old_ip, eee->device.ip_addr); } #ifdef __ANDROID_NDK__