(void)meshlink_errno;
}
+ /// This functions is called whenever MeshLink is blacklisted by another node.
+ virtual void blacklisted(node *peer) {
+ /* do nothing */
+ (void)peer;
+ }
+
/// This functions is called whenever MeshLink a meta-connection attempt is made.
virtual void connection_try(node *peer) {
/* do nothing */
meshlink_set_node_duplicate_cb(handle, &node_duplicate_trampoline);
meshlink_set_log_cb(handle, MESHLINK_DEBUG, &log_trampoline);
meshlink_set_error_cb(handle, &error_trampoline);
+ meshlink_set_blacklisted_cb(handle, &blacklisted_trampoline);
meshlink_set_channel_listen_cb(handle, &channel_listen_trampoline);
meshlink_set_channel_accept_cb(handle, &channel_accept_trampoline);
meshlink_set_connection_try_cb(handle, &connection_try_trampoline);
that->error(meshlink_errno);
}
+ static void blacklisted_trampoline(meshlink_handle_t *handle, meshlink_node_t *peer) {
+ if(!(handle->priv)) {
+ return;
+ }
+
+ meshlink::mesh *that = static_cast<mesh *>(handle->priv);
+ that->blacklisted(static_cast<node *>(peer));
+ }
+
static void connection_try_trampoline(meshlink_handle_t *handle, meshlink_node_t *peer) {
if(!(handle->priv)) {
return;
pthread_mutex_unlock(&mesh->mutex);
}
+void meshlink_set_blacklisted_cb(struct meshlink_handle *mesh, meshlink_blacklisted_cb_t cb) {
+ if(!mesh) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return;
+ }
+
+ if(pthread_mutex_lock(&mesh->mutex) != 0) {
+ abort();
+ }
+
+ mesh->blacklisted_cb = cb;
+ pthread_mutex_unlock(&mesh->mutex);
+}
+
static bool prepare_packet(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, size_t len, vpn_packet_t *packet) {
meshlink_packethdr_t *hdr;
*/
void meshlink_set_error_cb(struct meshlink_handle *mesh, meshlink_error_cb_t cb);
+/// A callback for receiving blacklisted conditions encountered by the MeshLink thread.
+/** @param mesh A handle which represents an instance of MeshLink, or NULL.
+ * @param node The node that blacklisted the local node.
+ */
+typedef void (*meshlink_blacklisted_cb_t)(struct meshlink_handle *mesh, struct meshlink_node *node);
+
+/// Set the blacklisted callback.
+/** This functions sets the callback that is called whenever MeshLink detects that it is blacklisted by another node.
+ *
+ * The callback is run in MeshLink's own thread.
+ * It is important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
+ * to hand the data over to the application's thread.
+ * The callback should also not block itself and return as quickly as possible.
+ *
+ * \memberof meshlink_handle
+ * @param mesh A handle which represents an instance of MeshLink, or NULL.
+ * @param cb A pointer to the function which will be called when a serious error is encountered.
+ * If a NULL pointer is given, the callback will be disabled.
+ */
+void meshlink_set_blacklisted_cb(struct meshlink_handle *mesh, meshlink_blacklisted_cb_t cb);
+
/// Send data to another node.
/** This functions sends one packet of data to another node in the mesh.
* The packet is sent using UDP semantics, which means that
meshlink_open_params_set_storage_key
meshlink_reset_timers
meshlink_send
+meshlink_set_blacklisted_cb
meshlink_set_canonical_address
meshlink_set_channel_accept_cb
meshlink_set_channel_listen_cb
meshlink_node_duplicate_cb_t node_duplicate_cb;
meshlink_connection_try_cb_t connection_try_cb;
meshlink_error_cb_t error_cb;
+ meshlink_blacklisted_cb_t blacklisted_cb;
// Mesh parameters
char *appname;
void handle_meta_connection_data(struct meshlink_handle *mesh, struct connection_t *);
void retry(struct meshlink_handle *mesh);
int check_port(struct meshlink_handle *mesh);
+void flush_meta(struct meshlink_handle *mesh, struct connection_t *);
#ifndef HAVE_MINGW
#define closesocket(s) close(s)
}
}
+void flush_meta(meshlink_handle_t *mesh, connection_t *c) {
+ handle_meta_write(mesh, c);
+}
+
static void handle_meta_io(event_loop_t *loop, void *data, int flags) {
meshlink_handle_t *mesh = loop->data;
connection_t *c = data;
logger(mesh, MESHLINK_DEBUG, "Got %s from %s: %s", request_name[reqno], c->name, request);
}
- if((c->allow_request != ALL) && (c->allow_request != reqno)) {
+ if((c->allow_request != ALL) && (c->allow_request != reqno) && (reqno != ERROR)) {
logger(mesh, MESHLINK_ERROR, "Unauthorized request from %s", c->name);
return false;
}
LAST /* Guardian for the highest request number */
} request_t;
+typedef enum request_error_t {
+ NONE = 0,
+ BLACKLISTED = 1,
+} request_error_t;
+
typedef struct past_request_t {
const char *request;
time_t firstseen;
bool send_id(struct meshlink_handle *mesh, struct connection_t *);
bool send_ack(struct meshlink_handle *mesh, struct connection_t *);
+bool send_error(struct meshlink_handle *mesh, struct connection_t *, request_error_t, const char *);
bool send_ping(struct meshlink_handle *mesh, struct connection_t *);
bool send_pong(struct meshlink_handle *mesh, struct connection_t *);
bool send_add_edge(struct meshlink_handle *mesh, struct connection_t *, const struct edge_t *, int contradictions);
return false;
}
- if(n->status.blacklisted) {
- logger(mesh, MESHLINK_WARNING, "Peer %s is blacklisted", c->name);
- return false;
- }
-
if(!node_read_public_key(mesh, n)) {
logger(mesh, MESHLINK_ERROR, "No key known for peer %s", c->name);
}
bool send_ack(meshlink_handle_t *mesh, connection_t *c) {
+ node_t *n = lookup_node(mesh, c->name);
+
+ if(n && n->status.blacklisted) {
+ logger(mesh, MESHLINK_WARNING, "Peer %s is blacklisted", c->name);
+ return send_error(mesh, c, BLACKLISTED, "blacklisted");
+ }
+
c->last_ping_time = mesh->loop.now.tv_sec;
return send_request(mesh, c, NULL, "%d %s %d %x", ACK, mesh->myport, mesh->devclass, OPTION_PMTU_DISCOVERY | (PROT_MINOR << 24));
}
return true;
}
+bool send_error(meshlink_handle_t *mesh, connection_t *c, request_error_t err, const char *message) {
+ send_request(mesh, c, NULL, "%d %d %s", ERROR, err, message);
+ flush_meta(mesh, c);
+ return false;
+}
+
bool error_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
assert(request);
assert(*request);
logger(mesh, MESHLINK_INFO, "Error message from %s: %d: %s", c->name, err, errorstring);
+ switch(err) {
+ case BLACKLISTED:
+ if(mesh->blacklisted_cb) {
+ mesh->blacklisted_cb(mesh, (meshlink_node_t *)lookup_node(mesh, c->name));
+ }
+ }
+
return false;
}
static struct sync_flag bar_connected;
static struct sync_flag bar_disconnected;
+static struct sync_flag bar_blacklisted;
static struct sync_flag baz_connected;
static void foo_status_cb(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) {
}
}
+static void bar_blacklisted_cb(meshlink_handle_t *mesh, meshlink_node_t *node) {
+ (void)mesh;
+
+ if(!strcmp(node->name, "foo")) {
+ set_sync_flag(&bar_blacklisted, true);
+ }
+}
+
int main(void) {
init_sync_flag(&bar_connected);
init_sync_flag(&bar_disconnected);
// Blacklist bar
+ meshlink_set_blacklisted_cb(mesh[1], bar_blacklisted_cb);
+
set_sync_flag(&bar_disconnected, false);
assert(meshlink_blacklist(mesh[0], meshlink_get_node(mesh[0], name[1])));
assert(wait_sync_flag(&bar_disconnected, 5));
assert(meshlink_get_node_blacklisted(mesh[0], meshlink_get_node(mesh[0], name[1])));
+ assert(wait_sync_flag(&bar_blacklisted, 10));
+
// Whitelist bar
set_sync_flag(&bar_connected, false);