Browse Source

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.
pull/282/head
emanuele-f 4 years ago
parent
commit
346631ffe8
  1. 37
      include/n2n.h
  2. 108
      src/edge_utils.c

37
include/n2n.h

@ -215,6 +215,36 @@ typedef struct n2n_route {
in_addr_t gateway; in_addr_t gateway;
} n2n_route_t; } 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 { typedef struct n2n_edge_conf {
n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES]; n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
n2n_route_t *routes; /**< Networks to route through n2n */ n2n_route_t *routes; /**< Networks to route through n2n */
@ -238,8 +268,6 @@ typedef struct n2n_edge_conf {
int mgmt_port; int mgmt_port;
} n2n_edge_conf_t; } n2n_edge_conf_t;
typedef struct n2n_edge n2n_edge_t; /* Opaque, see edge_utils.c */
typedef struct sn_stats typedef struct sn_stats
{ {
size_t errors; /* Number of errors encountered. */ size_t errors; /* Number of errors encountered. */
@ -351,6 +379,11 @@ void edge_term_conf(n2n_edge_conf_t *conf);
/* Public functions */ /* Public functions */
n2n_edge_t* edge_init(const tuntap_dev *dev, const n2n_edge_conf_t *conf, int *rv); 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_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 run_edge_loop(n2n_edge_t *eee, int *keep_running);
int quick_edge_init(char *device_name, char *community_name, int quick_edge_init(char *device_name, char *community_name,
char *encrypt_key, char *device_mac, char *encrypt_key, char *device_mac,

108
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) { int edge_verify_conf(const n2n_edge_conf_t *conf) {
if(conf->community_name[0] == 0) if(conf->community_name[0] == 0)
return(-1); return(-1);
@ -90,6 +84,8 @@ struct n2n_edge {
n2n_trans_op_t transop; /**< The transop to use when encoding */ n2n_trans_op_t transop; /**< The transop to use when encoding */
n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */ 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 */ /* Sockets */
n2n_sock_t supernode; n2n_sock_t supernode;
@ -102,11 +98,6 @@ struct n2n_edge {
int multicast_joined; /**< 1 if the group has been joined.*/ int multicast_joined; /**< 1 if the group has been joined.*/
#endif #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 */ /* Peers */
struct peer_info * known_peers; /**< Edges we are connected to. */ struct peer_info * known_peers; /**< Edges we are connected to. */
struct peer_info * pending_peers; /**< Edges we have tried to register with. */ 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) { const char* transop_str(enum n2n_transform tr) {
switch(tr) { switch(tr) {
case N2N_TRANSFORM_ID_NULL: return("null"); 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); rc = n2n_transop_cc20_init(&eee->conf, &eee->transop);
break; break;
#endif #endif
#ifndef __ANDROID_NDK__
case N2N_TRANSFORM_ID_SPECK: case N2N_TRANSFORM_ID_SPECK:
rc = n2n_transop_speck_init(&eee->conf, &eee->transop); rc = n2n_transop_speck_init(&eee->conf, &eee->transop);
break; break;
#endif
default: default:
rc = n2n_transop_null_init(&eee->conf, &eee->transop); 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)); 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; eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
} }
else else
@ -1098,18 +1094,13 @@ static int handle_PACKET(n2n_edge_t * eee,
} }
} }
#ifdef __ANDROID_NDK__ if(eee->cb.packet_from_peer) {
if((psize >= 36) && if(eee->cb.packet_from_peer(eee, orig_sender, eth_payload, eth_size) == N2N_DROP) {
(ntohs(*((uint16_t*)&eth_payload[12])) == 0x0806) && /* ARP */ traceEvent(TRACE_DEBUG, "DROP packet %u", (unsigned int)eth_size);
(ntohs(*((uint16_t*)&eth_payload[20])) == 0x0002) && /* REPLY */
(!memcmp(&eth_payload[28], &eee->gateway_ip, 4))) { /* From gateway */
memcpy(eee->gateway_mac, &eth_payload[22], 6);
traceEvent(TRACE_INFO, "Gateway MAC: %02X:%02X:%02X:%02X:%02X:%02X", return(0);
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. */ /* Write ethernet packet to tap device. */
traceEvent(TRACE_DEBUG, "sending to TAP %u", (unsigned int)eth_size); 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. */ /** 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) { uint8_t *tap_pkt, size_t len) {
ipstr_t ip_buf; ipstr_t ip_buf;
n2n_mac_t destMac; n2n_mac_t destMac;
@ -1400,13 +1391,6 @@ static void send_packet2net(n2n_edge_t * eee,
ether_hdr_t eh; 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 */ /* tap_pkt is not aligned so we have to copy to aligned memory */
memcpy(&eh, tap_pkt, sizeof(ether_hdr_t)); 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 /** Read a single packet from the TAP interface, process it and write out the
* corresponding packet to the cooked socket. * corresponding packet to the cooked socket.
*/ */
static void readFromTAPSocket(n2n_edge_t * eee) { void edge_read_from_tap(n2n_edge_t * eee) {
/* tun -> remote */ /* tun -> remote */
uint8_t eth_pkt[N2N_PKT_BUF_SIZE]; uint8_t eth_pkt[N2N_PKT_BUF_SIZE];
macstr_t mac_buf; macstr_t mac_buf;
@ -1572,7 +1556,15 @@ static void readFromTAPSocket(n2n_edge_t * eee) {
} }
else 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 */ /* Another edge is registering with us */
n2n_REGISTER_t reg; n2n_REGISTER_t reg;
n2n_mac_t null_mac = { '\0' };
int via_multicast; int via_multicast;
decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx); decode_REGISTER(&reg, &cmn, udp_buf, &rem, &idx);
@ -1780,20 +1771,8 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) {
eee->sn_wait=0; eee->sn_wait=0;
eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */ eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */
#ifdef __ANDROID_NDK__ if(eee->cb.sn_registration_updated)
int change = 0; eee->cb.sn_registration_updated(eee, now, &sender);
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 /* NOTE: the register_interval should be chosen by the edge node
* based on its NAT configuration. */ * 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 * 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 * 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) { while(*keep_running) {
@ -1943,7 +1922,7 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
#ifdef __ANDROID_NDK__ #ifdef __ANDROID_NDK__
if(uip_arp_len != 0) { if(uip_arp_len != 0) {
readFromTAPSocket(eee); edge_read_from_tap(eee);
uip_arp_len = 0; uip_arp_len = 0;
} }
#endif /* #ifdef __ANDROID_NDK__ */ #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)) { if(FD_ISSET(eee->device.fd, &socket_mask)) {
/* Read an ethernet frame from the TAP socket. Write on the IP /* Read an ethernet frame from the TAP socket. Write on the IP
* socket. */ * socket. */
readFromTAPSocket(eee); edge_read_from_tap(eee);
} }
#endif #endif
} }
@ -1978,9 +1957,14 @@ int run_edge_loop(n2n_edge_t * eee, int *keep_running) {
if(eee->conf.dyn_ip_mode && if(eee->conf.dyn_ip_mode &&
((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) { ((nowTime - lastIfaceCheck) > IFACE_UPDATE_INTERVAL)) {
uint32_t old_ip = eee->device.ip_addr;
traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address."); traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address.");
tuntap_get_address(&(eee->device)); tuntap_get_address(&(eee->device));
lastIfaceCheck = nowTime; 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__ #ifdef __ANDROID_NDK__

Loading…
Cancel
Save