edge_management.c (n2n-3.0) | : | edge_management.c (n2n-3.1.1) | ||
---|---|---|---|---|
/** | /** | |||
* (C) 2007-21 - ntop.org and contributors | * (C) 2007-22 - ntop.org and contributors | |||
* | * | |||
* This program is free software; you can redistribute it and/or modify | * This program is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation; either version 3 of the License, or | * the Free Software Foundation; either version 3 of the License, or | |||
* (at your option) any later version. | * (at your option) any later version. | |||
* | * | |||
* This program is distributed in the hope that it will be useful, | * This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | * GNU General Public License for more details. | |||
* | * | |||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | |||
* along with this program; if not see see <http://www.gnu.org/licenses/> | * along with this program; if not see see <http://www.gnu.org/licenses/> | |||
* | * | |||
*/ | */ | |||
#include "n2n.h" | #include "n2n.h" | |||
#include "edge_utils_win32.h" | #include "edge_utils_win32.h" | |||
typedef struct strbuf { | ||||
size_t size; | ||||
char str[]; | ||||
} strbuf_t; | ||||
#define STRBUF_INIT(buf,p) do { \ | ||||
buf = (void *)p; \ | ||||
buf->size = sizeof(*p) - sizeof(size_t); \ | ||||
} while(0) | ||||
enum n2n_mgmt_type { | ||||
N2N_MGMT_UNKNOWN = 0, | ||||
N2N_MGMT_READ = 1, | ||||
N2N_MGMT_WRITE = 2, | ||||
N2N_MGMT_SUB = 3, | ||||
}; | ||||
/* | ||||
* Everything needed to reply to a request | ||||
*/ | ||||
typedef struct mgmt_req { | ||||
n2n_edge_t *eee; | ||||
enum n2n_mgmt_type type; | ||||
char tag[10]; | ||||
struct sockaddr_in sender_sock; | ||||
} mgmt_req_t; | ||||
/* | ||||
* Read/Write handlers are defined in this structure | ||||
*/ | ||||
#define FLAG_WROK 1 | #define FLAG_WROK 1 | |||
typedef struct n2n_mgmt_handler { | typedef struct mgmt_handler { | |||
int flags; | int flags; | |||
char *cmd; | char *cmd; | |||
char *help; | char *help; | |||
void (*func)(n2n_edge_t *eee, char *udp_buf, struct sockaddr_in sender_sock, | void (*func)(mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv); | |||
enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); | } mgmt_handler_t; | |||
} n2n_mgmt_handler_t; | ||||
static void mgmt_error (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in | /* | |||
sender_sock, char *tag, char *msg) { | * Event topic names are defined in this structure | |||
size_t msg_len; | */ | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | typedef struct mgmt_events { | |||
"{" | enum n2n_event_topic topic; | |||
"\"_tag\":\"%s\"," | char *cmd; | |||
"\"_type\":\"error\"," | char *help; | |||
"\"error\":\"%s\"}\n", | } mgmt_events_t; | |||
tag, | ||||
msg); | // Lookup the index of matching argv0 in a cmd list | |||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | // store index in "Result", or -1 for not found | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | #define lookup_handler(Result, list, argv0) do { \ | |||
int nr_max = sizeof(list) / sizeof(list[0]); \ | ||||
for( Result=0; Result < nr_max; Result++ ) { \ | ||||
if(0 == strcmp(list[Result].cmd, argv0)) { \ | ||||
break; \ | ||||
} \ | ||||
} \ | ||||
if( Result >= nr_max ) { \ | ||||
Result = -1; \ | ||||
} \ | ||||
} while(0) | ||||
ssize_t send_reply (mgmt_req_t *req, strbuf_t *buf, size_t msg_len) { | ||||
// TODO: better error handling (counters?) | ||||
return sendto(req->eee->udp_mgmt_sock, buf->str, msg_len, 0, | ||||
(struct sockaddr *) &req->sender_sock, sizeof(struct sockaddr_ | ||||
in)); | ||||
} | ||||
size_t gen_json_1str (strbuf_t *buf, char *tag, char *_type, char *key, char *va | ||||
l) { | ||||
return snprintf(buf->str, buf->size, | ||||
"{" | ||||
"\"_tag\":\"%s\"," | ||||
"\"_type\":\"%s\"," | ||||
"\"%s\":\"%s\"}\n", | ||||
tag, | ||||
_type, | ||||
key, | ||||
val); | ||||
} | ||||
size_t gen_json_1uint (strbuf_t *buf, char *tag, char *_type, char *key, unsigne | ||||
d int val) { | ||||
return snprintf(buf->str, buf->size, | ||||
"{" | ||||
"\"_tag\":\"%s\"," | ||||
"\"_type\":\"%s\"," | ||||
"\"%s\":%u}\n", | ||||
tag, | ||||
_type, | ||||
key, | ||||
val); | ||||
} | ||||
static void send_json_1str (mgmt_req_t *req, strbuf_t *buf, char *_type, char *k | ||||
ey, char *val) { | ||||
size_t msg_len = gen_json_1str(buf, req->tag, _type, key, val); | ||||
send_reply(req, buf, msg_len); | ||||
} | ||||
static void send_json_1uint (mgmt_req_t *req, strbuf_t *buf, char *_type, char * | ||||
key, unsigned int val) { | ||||
size_t msg_len = gen_json_1uint(buf, req->tag, _type, key, val); | ||||
send_reply(req, buf, msg_len); | ||||
} | } | |||
static void mgmt_stop (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in | size_t event_debug (strbuf_t *buf, char *tag, int data0, void *data1) { | |||
sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { | traceEvent(TRACE_DEBUG, "Unexpected call to event_debug"); | |||
size_t msg_len; | return 0; | |||
} | ||||
if(type==N2N_MGMT_WRITE) { | size_t event_test (strbuf_t *buf, char *tag, int data0, void *data1) { | |||
*eee->keep_running = 0; | size_t msg_len = gen_json_1str(buf, tag, "event", "test", (char *)data1); | |||
} | return msg_len; | |||
} | ||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | size_t event_peer (strbuf_t *buf, char *tag, int data0, void *data1) { | |||
"{" | int action = data0; | |||
"\"_tag\":\"%s\"," | struct peer_info *peer = (struct peer_info *)data1; | |||
"\"_type\":\"row\"," | ||||
"\"keep_running\":%u}\n", | ||||
tag, | ||||
*eee->keep_running); | ||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | macstr_t mac_buf; | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | n2n_sock_str_t sockbuf; | |||
/* | ||||
* Just the peer_info bits that are needed for lookup (maccaddr) or | ||||
* firewall and routing (sockaddr) | ||||
* If needed, other details can be fetched via the edges method call. | ||||
*/ | ||||
return snprintf(buf->str, buf->size, | ||||
"{" | ||||
"\"_tag\":\"%s\"," | ||||
"\"_type\":\"event\"," | ||||
"\"action\":%i," | ||||
"\"macaddr\":\"%s\"," | ||||
"\"sockaddr\":\"%s\"}\n", | ||||
tag, | ||||
action, | ||||
(is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, pe | ||||
er->mac_addr), | ||||
sock_to_cstr(sockbuf, &(peer->sock))); | ||||
} | } | |||
static void mgmt_verbose (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_ | static void mgmt_error (mgmt_req_t *req, strbuf_t *buf, char *msg) { | |||
in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { | send_json_1str(req, buf, "error", "error", msg); | |||
size_t msg_len; | } | |||
static void mgmt_stop (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) | ||||
{ | ||||
if(req->type==N2N_MGMT_WRITE) { | ||||
*req->eee->keep_running = 0; | ||||
} | ||||
send_json_1uint(req, buf, "row", "keep_running", *req->eee->keep_running); | ||||
} | ||||
if(type==N2N_MGMT_WRITE) { | static void mgmt_verbose (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *arg | |||
v) { | ||||
if(req->type==N2N_MGMT_WRITE) { | ||||
if(argv) { | if(argv) { | |||
setTraceLevel(strtoul(argv, NULL, 0)); | setTraceLevel(strtoul(argv, NULL, 0)); | |||
} | } | |||
} | } | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | send_json_1uint(req, buf, "row", "traceLevel", getTraceLevel()); | |||
"{" | ||||
"\"_tag\":\"%s\"," | ||||
"\"_type\":\"row\"," | ||||
"\"traceLevel\":%u}\n", | ||||
tag, | ||||
getTraceLevel()); | ||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | ||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
} | } | |||
static void mgmt_communities (n2n_edge_t *eee, char *udp_buf, const struct socka | static void mgmt_communities (mgmt_req_t *req, strbuf_t *buf, char *argv0, char | |||
ddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) | *argv) { | |||
{ | ||||
size_t msg_len; | ||||
if(eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) { | if(req->eee->conf.header_encryption != HEADER_ENCRYPTION_NONE) { | |||
mgmt_error(eee, udp_buf, sender_sock, tag, "noaccess"); | mgmt_error(req, buf, "noaccess"); | |||
return; | return; | |||
} | } | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | send_json_1str(req, buf, "row", "community", (char *)req->eee->conf.communit | |||
"{" | y_name); | |||
"\"_tag\":\"%s\"," | ||||
"\"_type\":\"row\"," | ||||
"\"community\":\"%s\"}", | ||||
tag, | ||||
eee->conf.community_name); | ||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | ||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
} | } | |||
static void mgmt_supernodes (n2n_edge_t *eee, char *udp_buf, const struct sockad dr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { | static void mgmt_supernodes (mgmt_req_t *req, strbuf_t *buf, char *argv0, char * argv) { | |||
size_t msg_len; | size_t msg_len; | |||
struct peer_info *peer, *tmpPeer; | struct peer_info *peer, *tmpPeer; | |||
macstr_t mac_buf; | macstr_t mac_buf; | |||
n2n_sock_str_t sockbuf; | n2n_sock_str_t sockbuf; | |||
selection_criterion_str_t sel_buf; | selection_criterion_str_t sel_buf; | |||
HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) { | HASH_ITER(hh, req->eee->conf.supernodes, peer, tmpPeer) { | |||
/* | /* | |||
* TODO: | * TODO: | |||
* The version string provided by the remote supernode could contain | * The version string provided by the remote supernode could contain | |||
* chars that make our JSON invalid. | * chars that make our JSON invalid. | |||
* - do we care? | * - do we care? | |||
*/ | */ | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | msg_len = snprintf(buf->str, buf->size, | |||
"{" | "{" | |||
"\"_tag\":\"%s\"," | "\"_tag\":\"%s\"," | |||
"\"_type\":\"row\"," | "\"_type\":\"row\"," | |||
"\"version\":\"%s\"," | "\"version\":\"%s\"," | |||
"\"purgeable\":%i," | "\"purgeable\":%i," | |||
"\"current\":%i," | "\"current\":%i," | |||
"\"macaddr\":\"%s\"," | "\"macaddr\":\"%s\"," | |||
"\"sockaddr\":\"%s\"," | "\"sockaddr\":\"%s\"," | |||
"\"selection\":\"%s\"," | "\"selection\":\"%s\"," | |||
"\"last_seen\":%li," | "\"last_seen\":%li," | |||
"\"uptime\":%li}\n", | "\"uptime\":%li}\n", | |||
tag, | req->tag, | |||
peer->version, | peer->version, | |||
peer->purgeable, | peer->purgeable, | |||
(peer == eee->curr_sn) ? (eee->sn_wait ? 2 : 1 ) : 0, | (peer == req->eee->curr_sn) ? (req->eee->sn_wait ? 2 : 1 ) : 0, | |||
is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_bu f, peer->mac_addr), | is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_bu f, peer->mac_addr), | |||
sock_to_cstr(sockbuf, &(peer->sock)), | sock_to_cstr(sockbuf, &(peer->sock)), | |||
sn_selection_criterion_str(eee, sel_buf, peer), | sn_selection_criterion_str(req->eee, sel_buf, peer), | |||
peer->last_seen, | peer->last_seen, | |||
peer->uptime); | peer->uptime); | |||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | send_reply(req, buf, msg_len); | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
} | } | |||
} | } | |||
static void mgmt_edges_row (n2n_edge_t *eee, char *udp_buf, const struct sockadd r_in sender_sock, char *tag, struct peer_info *peer, char *mode) { | static void mgmt_edges_row (mgmt_req_t *req, strbuf_t *buf, struct peer_info *pe er, char *mode) { | |||
size_t msg_len; | size_t msg_len; | |||
macstr_t mac_buf; | macstr_t mac_buf; | |||
n2n_sock_str_t sockbuf; | n2n_sock_str_t sockbuf; | |||
dec_ip_bit_str_t ip_bit_str = {'\0'}; | dec_ip_bit_str_t ip_bit_str = {'\0'}; | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | msg_len = snprintf(buf->str, buf->size, | |||
"{" | "{" | |||
"\"_tag\":\"%s\"," | "\"_tag\":\"%s\"," | |||
"\"_type\":\"row\"," | "\"_type\":\"row\"," | |||
"\"mode\":\"%s\"," | "\"mode\":\"%s\"," | |||
"\"ip4addr\":\"%s\"," | "\"ip4addr\":\"%s\"," | |||
"\"purgeable\":%i," | "\"purgeable\":%i," | |||
"\"local\":%i," | "\"local\":%i," | |||
"\"macaddr\":\"%s\"," | "\"macaddr\":\"%s\"," | |||
"\"sockaddr\":\"%s\"," | "\"sockaddr\":\"%s\"," | |||
"\"desc\":\"%s\"," | "\"desc\":\"%s\"," | |||
"\"last_p2p\":%li,\n" | "\"last_p2p\":%li,\n" | |||
"\"last_sent_query\":%li,\n" | "\"last_sent_query\":%li,\n" | |||
"\"last_seen\":%li}\n", | "\"last_seen\":%li}\n", | |||
tag, | req->tag, | |||
mode, | mode, | |||
(peer->dev_addr.net_addr == 0) ? "" : ip_subnet_to_str(ip _bit_str, &peer->dev_addr), | (peer->dev_addr.net_addr == 0) ? "" : ip_subnet_to_str(ip _bit_str, &peer->dev_addr), | |||
peer->purgeable, | peer->purgeable, | |||
peer->local, | peer->local, | |||
(is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), | (is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac_buf, peer->mac_addr), | |||
sock_to_cstr(sockbuf, &(peer->sock)), | sock_to_cstr(sockbuf, &(peer->sock)), | |||
peer->dev_desc, | peer->dev_desc, | |||
peer->last_p2p, | peer->last_p2p, | |||
peer->last_sent_query, | peer->last_sent_query, | |||
peer->last_seen); | peer->last_seen); | |||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0 /*flags*/, | send_reply(req, buf, msg_len); | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
} | } | |||
static void mgmt_edges (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { | static void mgmt_edges (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { | |||
struct peer_info *peer, *tmpPeer; | struct peer_info *peer, *tmpPeer; | |||
// dump nodes with forwarding through supernodes | // dump nodes with forwarding through supernodes | |||
HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) { | HASH_ITER(hh, req->eee->pending_peers, peer, tmpPeer) { | |||
mgmt_edges_row(eee, udp_buf, sender_sock, tag, peer, "pSp"); | mgmt_edges_row(req, buf, peer, "pSp"); | |||
} | } | |||
// dump peer-to-peer nodes | // dump peer-to-peer nodes | |||
HASH_ITER(hh, eee->known_peers, peer, tmpPeer) { | HASH_ITER(hh, req->eee->known_peers, peer, tmpPeer) { | |||
mgmt_edges_row(eee, udp_buf, sender_sock, tag, peer, "p2p"); | mgmt_edges_row(req, buf, peer, "p2p"); | |||
} | } | |||
} | } | |||
static void mgmt_timestamps (n2n_edge_t *eee, char *udp_buf, const struct sockad dr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { | static void mgmt_timestamps (mgmt_req_t *req, strbuf_t *buf, char *argv0, char * argv) { | |||
size_t msg_len; | size_t msg_len; | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | msg_len = snprintf(buf->str, buf->size, | |||
"{" | "{" | |||
"\"_tag\":\"%s\"," | "\"_tag\":\"%s\"," | |||
"\"_type\":\"row\"," | "\"_type\":\"row\"," | |||
"\"start_time\":%lu," | "\"start_time\":%lu," | |||
"\"last_super\":%ld," | "\"last_super\":%ld," | |||
"\"last_p2p\":%ld}\n", | "\"last_p2p\":%ld}\n", | |||
tag, | req->tag, | |||
eee->start_time, | req->eee->start_time, | |||
eee->last_sup, | req->eee->last_sup, | |||
eee->last_p2p); | req->eee->last_p2p); | |||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | send_reply(req, buf, msg_len); | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
} | } | |||
static void mgmt_packetstats (n2n_edge_t *eee, char *udp_buf, const struct socka ddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { | static void mgmt_packetstats (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) { | |||
size_t msg_len; | size_t msg_len; | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | msg_len = snprintf(buf->str, buf->size, | |||
"{" | "{" | |||
"\"_tag\":\"%s\"," | "\"_tag\":\"%s\"," | |||
"\"_type\":\"row\"," | "\"_type\":\"row\"," | |||
"\"type\":\"transop\"," | "\"type\":\"transop\"," | |||
"\"tx_pkt\":%lu," | "\"tx_pkt\":%lu," | |||
"\"rx_pkt\":%lu}\n", | "\"rx_pkt\":%lu}\n", | |||
tag, | req->tag, | |||
eee->transop.tx_cnt, | req->eee->transop.tx_cnt, | |||
eee->transop.rx_cnt); | req->eee->transop.rx_cnt); | |||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | send_reply(req, buf, msg_len); | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | msg_len = snprintf(buf->str, buf->size, | |||
"{" | "{" | |||
"\"_tag\":\"%s\"," | "\"_tag\":\"%s\"," | |||
"\"_type\":\"row\"," | "\"_type\":\"row\"," | |||
"\"type\":\"p2p\"," | "\"type\":\"p2p\"," | |||
"\"tx_pkt\":%u," | "\"tx_pkt\":%u," | |||
"\"rx_pkt\":%u}\n", | "\"rx_pkt\":%u}\n", | |||
tag, | req->tag, | |||
eee->stats.tx_p2p, | req->eee->stats.tx_p2p, | |||
eee->stats.rx_p2p); | req->eee->stats.rx_p2p); | |||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | send_reply(req, buf, msg_len); | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | msg_len = snprintf(buf->str, buf->size, | |||
"{" | "{" | |||
"\"_tag\":\"%s\"," | "\"_tag\":\"%s\"," | |||
"\"_type\":\"row\"," | "\"_type\":\"row\"," | |||
"\"type\":\"super\"," | "\"type\":\"super\"," | |||
"\"tx_pkt\":%u," | "\"tx_pkt\":%u," | |||
"\"rx_pkt\":%u}\n", | "\"rx_pkt\":%u}\n", | |||
tag, | req->tag, | |||
eee->stats.tx_sup, | req->eee->stats.tx_sup, | |||
eee->stats.rx_sup); | req->eee->stats.rx_sup); | |||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | send_reply(req, buf, msg_len); | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | msg_len = snprintf(buf->str, buf->size, | |||
"{" | "{" | |||
"\"_tag\":\"%s\"," | "\"_tag\":\"%s\"," | |||
"\"_type\":\"row\"," | "\"_type\":\"row\"," | |||
"\"type\":\"super_broadcast\"," | "\"type\":\"super_broadcast\"," | |||
"\"tx_pkt\":%u," | "\"tx_pkt\":%u," | |||
"\"rx_pkt\":%u}\n", | "\"rx_pkt\":%u}\n", | |||
tag, | req->tag, | |||
eee->stats.tx_sup_broadcast, | req->eee->stats.tx_sup_broadcast, | |||
eee->stats.rx_sup_broadcast); | req->eee->stats.rx_sup_broadcast); | |||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | send_reply(req, buf, msg_len); | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
} | } | |||
static void mgmt_unimplemented (n2n_edge_t *eee, char *udp_buf, const struct soc kaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *arg v) { | static void mgmt_post_test (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *a rgv) { | |||
mgmt_error(eee, udp_buf, sender_sock, tag, "unimplemented"); | send_json_1str(req, buf, "row", "sending", "test"); | |||
mgmt_event_post(N2N_EVENT_TEST, -1, argv); | ||||
} | } | |||
static void mgmt_help (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv); | static void mgmt_unimplemented (mgmt_req_t *req, strbuf_t *buf, char *argv0, cha r *argv) { | |||
n2n_mgmt_handler_t mgmt_handlers[] = { | mgmt_error(req, buf, "unimplemented"); | |||
} | ||||
// Forward define so we can include this in the mgmt_handlers[] table | ||||
static void mgmt_help (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv); | ||||
static void mgmt_help_events (mgmt_req_t *req, strbuf_t *buf, char *argv0, char | ||||
*argv); | ||||
static const mgmt_handler_t mgmt_handlers[] = { | ||||
{ .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reserved for sup ernode", .func = mgmt_unimplemented}, | { .cmd = "reload_communities", .flags = FLAG_WROK, .help = "Reserved for sup ernode", .func = mgmt_unimplemented}, | |||
{ .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop}, | { .cmd = "stop", .flags = FLAG_WROK, .help = "Gracefully exit edge", .func = mgmt_stop}, | |||
{ .cmd = "verbose", .flags = FLAG_WROK, .help = "Manage verbosity level", .f unc = mgmt_verbose}, | { .cmd = "verbose", .flags = FLAG_WROK, .help = "Manage verbosity level", .f unc = mgmt_verbose}, | |||
{ .cmd = "communities", .help = "Show current community", .func = mgmt_commu nities}, | { .cmd = "communities", .help = "Show current community", .func = mgmt_commu nities}, | |||
{ .cmd = "edges", .help = "List current edges/peers", .func = mgmt_edges}, | { .cmd = "edges", .help = "List current edges/peers", .func = mgmt_edges}, | |||
{ .cmd = "supernodes", .help = "List current supernodes", .func = mgmt_super nodes}, | { .cmd = "supernodes", .help = "List current supernodes", .func = mgmt_super nodes}, | |||
{ .cmd = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps}, | { .cmd = "timestamps", .help = "Event timestamps", .func = mgmt_timestamps}, | |||
{ .cmd = "packetstats", .help = "traffic counters", .func = mgmt_packetstats }, | { .cmd = "packetstats", .help = "traffic counters", .func = mgmt_packetstats }, | |||
{ .cmd = "post.test", .help = "send a test event", .func = mgmt_post_test}, | ||||
{ .cmd = "help", .flags = FLAG_WROK, .help = "Show JSON commands", .func = m gmt_help}, | { .cmd = "help", .flags = FLAG_WROK, .help = "Show JSON commands", .func = m gmt_help}, | |||
{ .cmd = NULL }, | { .cmd = "help.events", .help = "Show available Subscribe topics", .func = m | |||
gmt_help_events}, | ||||
}; | ||||
/* Current subscriber for each event topic */ | ||||
static mgmt_req_t mgmt_event_subscribers[] = { | ||||
[N2N_EVENT_DEBUG] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, | ||||
[N2N_EVENT_TEST] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, | ||||
[N2N_EVENT_PEER] = { .eee = NULL, .type = N2N_MGMT_UNKNOWN, .tag = "\0" }, | ||||
}; | ||||
/* Map topic number to function */ | ||||
static const size_t (*mgmt_events[])(strbuf_t *buf, char *tag, int data0, void * | ||||
data1) = { | ||||
[N2N_EVENT_DEBUG] = event_debug, | ||||
[N2N_EVENT_TEST] = event_test, | ||||
[N2N_EVENT_PEER] = event_peer, | ||||
}; | ||||
/* Allow help and subscriptions to use topic name */ | ||||
static const mgmt_events_t mgmt_event_names[] = { | ||||
{ .cmd = "debug", .topic = N2N_EVENT_DEBUG, .help = "All events - for event | ||||
debugging"}, | ||||
{ .cmd = "test", .topic = N2N_EVENT_TEST, .help = "Used only by post.test"}, | ||||
{ .cmd = "peer", .topic = N2N_EVENT_PEER, .help = "Changes to peer list"}, | ||||
}; | }; | |||
static void mgmt_help (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in | void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1) { | |||
sender_sock, enum n2n_mgmt_type type, char *tag, char *argv0, char *argv) { | mgmt_req_t *debug = &mgmt_event_subscribers[N2N_EVENT_DEBUG]; | |||
mgmt_req_t *sub = &mgmt_event_subscribers[topic]; | ||||
traceEvent(TRACE_DEBUG, "post topic=%i data0=%i", topic, data0); | ||||
if( sub->type != N2N_MGMT_SUB && debug->type != N2N_MGMT_SUB) { | ||||
// If neither of this topic or the debug topic have a subscriber | ||||
// then we dont need to do any work | ||||
return; | ||||
} | ||||
char buf_space[100]; | ||||
strbuf_t *buf; | ||||
STRBUF_INIT(buf, buf_space); | ||||
char *tag; | ||||
if(sub->type == N2N_MGMT_SUB) { | ||||
tag = sub->tag; | ||||
} else { | ||||
tag = debug->tag; | ||||
} | ||||
size_t msg_len = mgmt_events[topic](buf, tag, data0, data1); | ||||
if(sub->type == N2N_MGMT_SUB) { | ||||
send_reply(sub, buf, msg_len); | ||||
} | ||||
if(debug->type == N2N_MGMT_SUB) { | ||||
send_reply(debug, buf, msg_len); | ||||
} | ||||
} | ||||
static void mgmt_help_events (mgmt_req_t *req, strbuf_t *buf, char *argv0, char | ||||
*argv) { | ||||
size_t msg_len; | ||||
int i; | ||||
int nr_handlers = sizeof(mgmt_event_names) / sizeof(mgmt_events_t); | ||||
for( i=0; i < nr_handlers; i++ ) { | ||||
int topic = mgmt_event_names[i].topic; | ||||
mgmt_req_t *sub = &mgmt_event_subscribers[topic]; | ||||
char host[40]; | ||||
char serv[6]; | ||||
if((sub->type != N2N_MGMT_SUB) || | ||||
getnameinfo((struct sockaddr *)&sub->sender_sock, sizeof(sub->sender_ | ||||
sock), | ||||
host, sizeof(host), | ||||
serv, sizeof(serv), | ||||
NI_NUMERICHOST|NI_NUMERICSERV) != 0) { | ||||
host[0] = '?'; | ||||
host[1] = 0; | ||||
serv[0] = '?'; | ||||
serv[1] = 0; | ||||
} | ||||
// TODO: handle a topic with no subscribers more cleanly | ||||
msg_len = snprintf(buf->str, buf->size, | ||||
"{" | ||||
"\"_tag\":\"%s\"," | ||||
"\"_type\":\"row\"," | ||||
"\"topic\":\"%s\"," | ||||
"\"tag\":\"%s\"," | ||||
"\"sockaddr\":\"%s:%s\"," | ||||
"\"help\":\"%s\"}\n", | ||||
req->tag, | ||||
mgmt_event_names[i].cmd, | ||||
sub->tag, | ||||
host, serv, | ||||
mgmt_event_names[i].help); | ||||
send_reply(req, buf, msg_len); | ||||
} | ||||
} | ||||
static void mgmt_help (mgmt_req_t *req, strbuf_t *buf, char *argv0, char *argv) | ||||
{ | ||||
size_t msg_len; | size_t msg_len; | |||
n2n_mgmt_handler_t *handler; | ||||
/* | /* | |||
* Even though this command is readonly, we deliberately do not check | * Even though this command is readonly, we deliberately do not check | |||
* the type - allowing help replies to both read and write requests | * the type - allowing help replies to both read and write requests | |||
*/ | */ | |||
for( handler=mgmt_handlers; handler->cmd; handler++ ) { | int i; | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | int nr_handlers = sizeof(mgmt_handlers) / sizeof(mgmt_handler_t); | |||
for( i=0; i < nr_handlers; i++ ) { | ||||
msg_len = snprintf(buf->str, buf->size, | ||||
"{" | "{" | |||
"\"_tag\":\"%s\"," | "\"_tag\":\"%s\"," | |||
"\"_type\":\"row\"," | "\"_type\":\"row\"," | |||
"\"cmd\":\"%s\"," | "\"cmd\":\"%s\"," | |||
"\"help\":\"%s\"}\n", | "\"help\":\"%s\"}\n", | |||
tag, | req->tag, | |||
handler->cmd, | mgmt_handlers[i].cmd, | |||
handler->help); | mgmt_handlers[i].help); | |||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | send_reply(req, buf, msg_len); | |||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
} | } | |||
} | } | |||
/* | /* | |||
* Check if the user is authorised for this command. | * Check if the user is authorised for this command. | |||
* - this should be more configurable! | * - this should be more configurable! | |||
* - for the moment we use some simple heuristics: | * - for the moment we use some simple heuristics: | |||
* Reads are not dangerous, so they are simply allowed | * Reads are not dangerous, so they are simply allowed | |||
* Writes are possibly dangerous, so they need a fake password | * Writes are possibly dangerous, so they need a fake password | |||
*/ | */ | |||
static int mgmt_auth (n2n_edge_t *eee, const struct sockaddr_in sender_sock, enu m n2n_mgmt_type type, char *auth, char *argv0, char *argv) { | static int mgmt_auth (mgmt_req_t *req, char *auth, char *argv0, char *argv) { | |||
if(auth) { | if(auth) { | |||
/* If we have an auth key, it must match */ | /* If we have an auth key, it must match */ | |||
if(eee->conf.mgmt_password_hash == pearson_hash_64((uint8_t*)auth, strle n(auth))) { | if(req->eee->conf.mgmt_password_hash == pearson_hash_64((uint8_t*)auth, strlen(auth))) { | |||
return 1; | return 1; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
/* if we dont have an auth key, we can still read */ | /* if we dont have an auth key, we can still read */ | |||
if(type == N2N_MGMT_READ) { | if(req->type == N2N_MGMT_READ) { | |||
return 1; | return 1; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in se nder_sock) { | static void handleMgmtJson (mgmt_req_t *req, char *udp_buf, const int recvlen) { | |||
strbuf_t *buf; | ||||
char cmdlinebuf[80]; | char cmdlinebuf[80]; | |||
enum n2n_mgmt_type type; | ||||
char *typechar; | char *typechar; | |||
char *options; | char *options; | |||
char *argv0; | char *argv0; | |||
char *argv; | char *argv; | |||
char *tag; | ||||
char *flagstr; | char *flagstr; | |||
int flags; | int flags; | |||
char *auth; | char *auth; | |||
n2n_mgmt_handler_t *handler; | ||||
size_t msg_len; | /* Initialise the tag field until we extract it from the cmdline */ | |||
req->tag[0] = '-'; | ||||
req->tag[1] = '1'; | ||||
req->tag[2] = '\0'; | ||||
/* save a copy of the commandline before we reuse the udp_buf */ | /* save a copy of the commandline before we reuse the udp_buf */ | |||
strncpy(cmdlinebuf, udp_buf, sizeof(cmdlinebuf)-1); | strncpy(cmdlinebuf, udp_buf, sizeof(cmdlinebuf)-1); | |||
cmdlinebuf[sizeof(cmdlinebuf)-1] = 0; | cmdlinebuf[sizeof(cmdlinebuf)-1] = 0; | |||
traceEvent(TRACE_DEBUG, "mgmt json %s", cmdlinebuf); | traceEvent(TRACE_DEBUG, "mgmt json %s", cmdlinebuf); | |||
/* we reuse the buffer already on the stack for all our strings */ | ||||
STRBUF_INIT(buf, udp_buf); | ||||
typechar = strtok(cmdlinebuf, " \r\n"); | typechar = strtok(cmdlinebuf, " \r\n"); | |||
if(!typechar) { | if(!typechar) { | |||
/* should not happen */ | /* should not happen */ | |||
mgmt_error(eee, udp_buf, sender_sock, "-1", "notype"); | mgmt_error(req, buf, "notype"); | |||
return; | return; | |||
} | } | |||
if(*typechar == 'r') { | if(*typechar == 'r') { | |||
type=N2N_MGMT_READ; | req->type=N2N_MGMT_READ; | |||
} else if(*typechar == 'w') { | } else if(*typechar == 'w') { | |||
type=N2N_MGMT_WRITE; | req->type=N2N_MGMT_WRITE; | |||
} else if(*typechar == 's') { | ||||
req->type=N2N_MGMT_SUB; | ||||
} else { | } else { | |||
/* dunno how we got here */ | mgmt_error(req, buf, "badtype"); | |||
mgmt_error(eee, udp_buf, sender_sock, "-1", "badtype"); | ||||
return; | return; | |||
} | } | |||
/* Extract the tag to use in all reply packets */ | /* Extract the tag to use in all reply packets */ | |||
options = strtok(NULL, " \r\n"); | options = strtok(NULL, " \r\n"); | |||
if(!options) { | if(!options) { | |||
mgmt_error(eee, udp_buf, sender_sock, "-1", "nooptions"); | mgmt_error(req, buf, "nooptions"); | |||
return; | return; | |||
} | } | |||
argv0 = strtok(NULL, " \r\n"); | argv0 = strtok(NULL, " \r\n"); | |||
if(!argv0) { | if(!argv0) { | |||
mgmt_error(eee, udp_buf, sender_sock, "-1", "nocmd"); | mgmt_error(req, buf, "nocmd"); | |||
return; | return; | |||
} | } | |||
/* | /* | |||
* The entire rest of the line is the argv. We apply no processing | * The entire rest of the line is the argv. We apply no processing | |||
* or arg separation so that the cmd can use it however it needs. | * or arg separation so that the cmd can use it however it needs. | |||
*/ | */ | |||
argv = strtok(NULL, "\r\n"); | argv = strtok(NULL, "\r\n"); | |||
/* | /* | |||
* There might be an auth token mixed in with the tag | * There might be an auth token mixed in with the tag | |||
*/ | */ | |||
tag = strtok(options, ":"); | char *tagp = strtok(options, ":"); | |||
strncpy(req->tag, tagp, sizeof(req->tag)-1); | ||||
req->tag[sizeof(req->tag)-1] = '\0'; | ||||
flagstr = strtok(NULL, ":"); | flagstr = strtok(NULL, ":"); | |||
if(flagstr) { | if(flagstr) { | |||
flags = strtoul(flagstr, NULL, 16); | flags = strtoul(flagstr, NULL, 16); | |||
} else { | } else { | |||
flags = 0; | flags = 0; | |||
} | } | |||
/* Only 1 flag bit defined at the moment - "auth option present" */ | /* Only 1 flag bit defined at the moment - "auth option present" */ | |||
if(flags & 1) { | if(flags & 1) { | |||
auth = strtok(NULL, ":"); | auth = strtok(NULL, ":"); | |||
} else { | } else { | |||
auth = NULL; | auth = NULL; | |||
} | } | |||
if(!mgmt_auth(eee, sender_sock, type, auth, argv0, argv)) { | if(!mgmt_auth(req, auth, argv0, argv)) { | |||
mgmt_error(eee, udp_buf, sender_sock, tag, "badauth"); | mgmt_error(req, buf, "badauth"); | |||
return; | return; | |||
} | } | |||
for( handler=mgmt_handlers; handler->cmd; handler++ ) { | if(req->type == N2N_MGMT_SUB) { | |||
if(0 == strcmp(handler->cmd, argv0)) { | int handler; | |||
break; | lookup_handler(handler, mgmt_event_names, argv0); | |||
if(handler == -1) { | ||||
mgmt_error(req, buf, "unknowntopic"); | ||||
return; | ||||
} | } | |||
int topic = mgmt_event_names[handler].topic; | ||||
if(mgmt_event_subscribers[topic].type == N2N_MGMT_SUB) { | ||||
send_json_1str(&mgmt_event_subscribers[topic], buf, | ||||
"unsubscribed", "topic", argv0); | ||||
send_json_1str(req, buf, "replacing", "topic", argv0); | ||||
} | ||||
memcpy(&mgmt_event_subscribers[topic], req, sizeof(*req)); | ||||
send_json_1str(req, buf, "subscribe", "topic", argv0); | ||||
return; | ||||
} | } | |||
if(!handler->cmd) { | ||||
mgmt_error(eee, udp_buf, sender_sock, tag, "unknowncmd"); | int handler; | |||
lookup_handler(handler, mgmt_handlers, argv0); | ||||
if(handler == -1) { | ||||
mgmt_error(req, buf, "unknowncmd"); | ||||
return; | return; | |||
} | } | |||
if((type==N2N_MGMT_WRITE) && !(handler->flags & FLAG_WROK)) { | if((req->type==N2N_MGMT_WRITE) && !(mgmt_handlers[handler].flags & FLAG_WROK | |||
mgmt_error(eee, udp_buf, sender_sock, tag, "readonly"); | )) { | |||
mgmt_error(req, buf, "readonly"); | ||||
return; | return; | |||
} | } | |||
/* | /* | |||
* TODO: | * TODO: | |||
* The tag provided by the requester could contain chars | * The tag provided by the requester could contain chars | |||
* that make our JSON invalid. | * that make our JSON invalid. | |||
* - do we care? | * - do we care? | |||
*/ | */ | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | send_json_1str(req, buf, "begin", "cmd", argv0); | |||
"{\"_tag\":\"%s\",\"_type\":\"begin\",\"cmd\":\"%s\"}\n", | ||||
tag, argv0); | ||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | ||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
handler->func(eee, udp_buf, sender_sock, type, tag, argv0, argv); | mgmt_handlers[handler].func(req, buf, argv0, argv); | |||
msg_len = snprintf(udp_buf, N2N_PKT_BUF_SIZE, | send_json_1str(req, buf, "end", "cmd", argv0); | |||
"{\"_tag\":\"%s\",\"_type\":\"end\"}\n", tag); | ||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | ||||
(struct sockaddr *) &sender_sock, sizeof(struct sockaddr_in)); | ||||
return; | return; | |||
} | } | |||
/** Read a datagram from the management UDP socket and take appropriate | ||||
* action. */ | ||||
void readFromMgmtSocket (n2n_edge_t *eee) { | ||||
char udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */ | ||||
ssize_t recvlen; | ||||
/* ssize_t sendlen; */ | ||||
mgmt_req_t req; | ||||
socklen_t i; | ||||
size_t msg_len; | ||||
time_t now; | ||||
struct peer_info *peer, *tmpPeer; | ||||
macstr_t mac_buf; | ||||
char time_buf[10]; /* 9 digits + 1 terminating zero */ | ||||
char uptime_buf[11]; /* 10 digits + 1 terminating zero */ | ||||
/* dec_ip_bit_str_t ip_bit_str = {'\0'}; */ | ||||
/* dec_ip_str_t ip_str = {'\0'}; */ | ||||
in_addr_t net; | ||||
n2n_sock_str_t sockbuf; | ||||
uint32_t num_pending_peers = 0; | ||||
uint32_t num_known_peers = 0; | ||||
uint32_t num = 0; | ||||
selection_criterion_str_t sel_buf; | ||||
req.eee = eee; | ||||
now = time(NULL); | ||||
i = sizeof(req.sender_sock); | ||||
recvlen = recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0 /*flags* | ||||
/, | ||||
(struct sockaddr *) &req.sender_sock, (socklen_t *) &i); | ||||
if(recvlen < 0) { | ||||
traceEvent(TRACE_WARNING, "mgmt recvfrom failed: %d - %s", errno, strerr | ||||
or(errno)); | ||||
return; /* failed to receive data from UDP */ | ||||
} | ||||
/* avoid parsing any uninitialized junk from the stack */ | ||||
udp_buf[recvlen] = 0; | ||||
if((0 == memcmp(udp_buf, "help", 4)) || (0 == memcmp(udp_buf, "?", 1))) { | ||||
strbuf_t *buf; | ||||
STRBUF_INIT(buf, &udp_buf); | ||||
msg_len = snprintf(buf->str, buf->size, | ||||
"Help for edge management console:\n" | ||||
"\tstop | Gracefully exit edge\n" | ||||
"\thelp | This help message\n" | ||||
"\t+verb | Increase verbosity of logging\n" | ||||
"\t-verb | Decrease verbosity of logging\n" | ||||
"\tr ... | start query with JSON reply\n" | ||||
"\tw ... | start update with JSON reply\n" | ||||
"\ts ... | subscribe to event channel JSON reply\n" | ||||
"\t<enter> | Display statistics\n\n"); | ||||
send_reply(&req, buf, msg_len); | ||||
return; | ||||
} | ||||
if(0 == memcmp(udp_buf, "stop", 4)) { | ||||
traceEvent(TRACE_NORMAL, "stop command received"); | ||||
*eee->keep_running = 0; | ||||
return; | ||||
} | ||||
if(0 == memcmp(udp_buf, "+verb", 5)) { | ||||
setTraceLevel(getTraceLevel() + 1); | ||||
traceEvent(TRACE_NORMAL, "+verb traceLevel=%u", (unsigned int) getTraceL | ||||
evel()); | ||||
strbuf_t *buf; | ||||
STRBUF_INIT(buf, &udp_buf); | ||||
msg_len = snprintf(buf->str, buf->size, | ||||
"> +OK traceLevel=%u\n", (unsigned int) getTraceLevel | ||||
()); | ||||
send_reply(&req, buf, msg_len); | ||||
return; | ||||
} | ||||
if(0 == memcmp(udp_buf, "-verb", 5)) { | ||||
strbuf_t *buf; | ||||
STRBUF_INIT(buf, &udp_buf); | ||||
if(getTraceLevel() > 0) { | ||||
setTraceLevel(getTraceLevel() - 1); | ||||
msg_len = snprintf(buf->str, buf->size, | ||||
"> -OK traceLevel=%u\n", getTraceLevel()); | ||||
} else { | ||||
msg_len = snprintf(buf->str, buf->size, | ||||
"> -NOK traceLevel=%u\n", getTraceLevel()); | ||||
} | ||||
traceEvent(TRACE_NORMAL, "-verb traceLevel=%u", (unsigned int) getTraceL | ||||
evel()); | ||||
send_reply(&req, buf, msg_len); | ||||
return; | ||||
} | ||||
if((udp_buf[0] >= 'a' && udp_buf[0] <= 'z') && (udp_buf[1] == ' ')) { | ||||
/* this is a JSON request */ | ||||
handleMgmtJson(&req, udp_buf, recvlen); | ||||
return; | ||||
} | ||||
traceEvent(TRACE_DEBUG, "mgmt status requested"); | ||||
msg_len = 0; | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"COMMUNITY '%s'\n\n", | ||||
(eee->conf.header_encryption == HEADER_ENCRYPTION_NONE) | ||||
? (char*)eee->conf.community_name : "-- header encrypted --"); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
" ### | TAP | MAC | EDGE | ||||
| HINT | LAST SEEN | UPTIME\n"); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"======================================================= | ||||
======================================================\n"); | ||||
// dump nodes with forwarding through supernodes | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"SUPERNODE FORWARD\n"); | ||||
num = 0; | ||||
HASH_ITER(hh, eee->pending_peers, peer, tmpPeer) { | ||||
++num_pending_peers; | ||||
net = htonl(peer->dev_addr.net_addr); | ||||
snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->l | ||||
ast_seen)); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - ms | ||||
g_len), | ||||
"%4u | %-15s | %-17s | %-21s | %-15s | %9s |\n", | ||||
++num, | ||||
(peer->dev_addr.net_addr == 0) ? "" : inet_ntoa(*(st | ||||
ruct in_addr *) &net), | ||||
(is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac | ||||
_buf, peer->mac_addr), | ||||
sock_to_cstr(sockbuf, &(peer->sock)), | ||||
peer->dev_desc, | ||||
(peer->last_seen) ? time_buf : ""); | ||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | ||||
(struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)) | ||||
; | ||||
msg_len = 0; | ||||
} | ||||
// dump peer-to-peer nodes | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"------------------------------------------------------- | ||||
------------------------------------------------------\n"); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"PEER TO PEER\n"); | ||||
num = 0; | ||||
HASH_ITER(hh, eee->known_peers, peer, tmpPeer) { | ||||
++num_known_peers; | ||||
net = htonl(peer->dev_addr.net_addr); | ||||
snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->l | ||||
ast_seen)); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - ms | ||||
g_len), | ||||
"%4u | %-15s | %-17s | %-21s | %-15s | %9s |\n", | ||||
++num, | ||||
(peer->dev_addr.net_addr == 0) ? "" : inet_ntoa(*(st | ||||
ruct in_addr *) &net), | ||||
(is_null_mac(peer->mac_addr)) ? "" : macaddr_str(mac | ||||
_buf, peer->mac_addr), | ||||
sock_to_cstr(sockbuf, &(peer->sock)), | ||||
peer->dev_desc, | ||||
(peer->last_seen) ? time_buf : ""); | ||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | ||||
(struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)) | ||||
; | ||||
msg_len = 0; | ||||
} | ||||
// dump supernodes | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"------------------------------------------------------- | ||||
------------------------------------------------------\n"); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"SUPERNODES\n"); | ||||
HASH_ITER(hh, eee->conf.supernodes, peer, tmpPeer) { | ||||
net = htonl(peer->dev_addr.net_addr); | ||||
snprintf(time_buf, sizeof(time_buf), "%9u", (unsigned int)(now - peer->l | ||||
ast_seen)); | ||||
snprintf(uptime_buf, sizeof(uptime_buf), "%10u", (unsigned int)(peer->up | ||||
time)); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - ms | ||||
g_len), | ||||
"%-19s %1s%1s | %-17s | %-21s | %-15s | %9s | %10s\n | ||||
", | ||||
peer->version, | ||||
(peer->purgeable == SN_UNPURGEABLE) ? "l" : "", | ||||
(peer == eee->curr_sn) ? (eee->sn_wait ? "." : "*" ) | ||||
: "", | ||||
is_null_mac(peer->mac_addr) ? "" : macaddr_str(mac_b | ||||
uf, peer->mac_addr), | ||||
sock_to_cstr(sockbuf, &(peer->sock)), | ||||
sn_selection_criterion_str(eee, sel_buf, peer), | ||||
(peer->last_seen) ? time_buf : "", | ||||
(peer->uptime) ? uptime_buf : ""); | ||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | ||||
(struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)) | ||||
; | ||||
msg_len = 0; | ||||
} | ||||
// further stats | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"======================================================= | ||||
======================================================\n"); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"uptime %lu | ", | ||||
time(NULL) - eee->start_time); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"pend_peers %u | ", | ||||
num_pending_peers); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"known_peers %u | ", | ||||
num_known_peers); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"transop %u,%u\n", | ||||
(unsigned int) eee->transop.tx_cnt, | ||||
(unsigned int) eee->transop.rx_cnt); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"super %u,%u | ", | ||||
(unsigned int) eee->stats.tx_sup, | ||||
(unsigned int) eee->stats.rx_sup); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"p2p %u,%u\n", | ||||
(unsigned int) eee->stats.tx_p2p, | ||||
(unsigned int) eee->stats.rx_p2p); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"last_super %ld sec ago | ", | ||||
(now - eee->last_sup)); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"last_p2p %ld sec ago\n", | ||||
(now - eee->last_p2p)); | ||||
msg_len += snprintf((char *) (udp_buf + msg_len), (N2N_PKT_BUF_SIZE - msg_le | ||||
n), | ||||
"\nType \"help\" to see more commands.\n\n"); | ||||
sendto(eee->udp_mgmt_sock, udp_buf, msg_len, 0, | ||||
(struct sockaddr *) &req.sender_sock, sizeof(struct sockaddr_in)); | ||||
} | ||||
End of changes. 82 change blocks. | ||||
163 lines changed or deleted | 381 lines changed or added |