From 6eaefb4dbce240334e35f67d9f3db5d4f44e49c9 Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Wed, 7 Nov 2007 02:49:25 +0000 Subject: [PATCH] Dump through control socket Note this removes SIGUSR1, SIGUSR2, and the graph dumping config option. It seems cleaner to do everything through the control socket. --- doc/tinc.conf.5.in | 12 ---------- doc/tinc.texi | 16 ------------- doc/tincctl.8.in | 2 +- doc/tincd.8.in | 4 ---- src/connection.c | 13 ++++++----- src/connection.h | 2 +- src/control.c | 32 +++++++++++++++++++++++++- src/control_common.h | 5 ++++ src/edge.c | 15 +++++++----- src/edge.h | 2 +- src/graph.c | 55 +++++++++++--------------------------------- src/graph.h | 2 +- src/net.c | 21 ----------------- src/node.c | 11 ++++----- src/node.h | 2 +- src/subnet.c | 10 ++++---- src/subnet.h | 2 +- src/tincctl.c | 32 ++++++++++++++++++++++++++ 18 files changed, 113 insertions(+), 125 deletions(-) diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index 978bdc17..83d2541c 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -147,18 +147,6 @@ instead of .Va Device . The info pages of the tinc package contain more information about configuring the virtual network device. -.It Va GraphDumpFile Li = Ar filename Bq experimental -If this option is present, -.Nm tinc -will dump the current network graph to the file -.Ar filename -every minute, unless there were no changes to the graph. -The file is in a format that can be read by graphviz tools. -If -.Ar filename -starts with a pipe symbol |, -then the rest of the filename is interpreted as a shell command -that is executed, the graph is then sent to stdin. .It Va Hostnames Li = yes | no Pq no This option selects whether IP addresses (both real and on the VPN) should be resolved. Since DNS lookups are blocking, it might affect tinc's diff --git a/doc/tinc.texi b/doc/tinc.texi index 2ea54be2..541d2de7 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -885,16 +885,6 @@ Under Windows, use @var{Interface} instead of @var{Device}. Note that you can only use one device per daemon. See also @ref{Device files}. -@cindex GraphDumpFile -@item GraphDumpFile = <@var{filename}> [experimental] -If this option is present, -tinc will dump the current network graph to the file @var{filename} -every minute, unless there were no changes to the graph. -The file is in a format that can be read by graphviz tools. -If @var{filename} starts with a pipe symbol |, -then the rest of the filename is interpreted as a shell command -that is executed, the graph is then sent to stdin. - @cindex Hostnames @item Hostnames = (no) This option selects whether IP addresses (both real and on the VPN) @@ -1579,12 +1569,6 @@ New outgoing connections specified in @file{tinc.conf} will be made. Temporarily increases debug level to 5. Send this signal again to revert to the original level. -@item USR1 -Dumps the connection list to syslog. - -@item USR2 -Dumps virtual network device statistics, all known nodes, edges and subnets to syslog. - @item WINCH Purges all information remembered about unreachable nodes. diff --git a/doc/tincctl.8.in b/doc/tincctl.8.in index eeb5031c..734bb4f5 100644 --- a/doc/tincctl.8.in +++ b/doc/tincctl.8.in @@ -78,7 +78,7 @@ Dump a graph of the VPN in format. .El .Sh BUGS -The "start", "restart", "reload", and "dump" commands are not yet implemented. +The "start", "restart", and "reload" commands are not yet implemented. .Pp If you find any bugs, report them to tinc@tinc-vpn.org. .Sh SEE ALSO diff --git a/doc/tincd.8.in b/doc/tincd.8.in index 37a134e0..f136a1bc 100644 --- a/doc/tincd.8.in +++ b/doc/tincd.8.in @@ -98,10 +98,6 @@ will be made. .It INT Temporarily increases debug level to 5. Send this signal again to revert to the original level. -.It USR1 -Dumps the connection list to syslog. -.It USR2 -Dumps virtual network device statistics, all known nodes, edges and subnets to syslog. .It WINCH Purges all information remembered about unreachable nodes. .El diff --git a/src/connection.c b/src/connection.c index 21cb6aa9..06f51b50 100644 --- a/src/connection.c +++ b/src/connection.c @@ -106,21 +106,22 @@ void connection_del(connection_t *c) { splay_delete(connection_tree, c); } -void dump_connections(void) { +int dump_connections(struct evbuffer *out) { splay_node_t *node; connection_t *c; cp(); - logger(LOG_DEBUG, _("Connections:")); - for(node = connection_tree->head; node; node = node->next) { c = node->data; - logger(LOG_DEBUG, _(" %s at %s options %lx socket %d status %04x"), - c->name, c->hostname, c->options, c->socket, c->status.value); + if(evbuffer_add_printf(out, + _(" %s at %s options %lx socket %d status %04x\n"), + c->name, c->hostname, c->options, c->socket, + c->status.value) == -1) + return errno; } - logger(LOG_DEBUG, _("End of connections.")); + return 0; } bool read_connection_config(connection_t *c) { diff --git a/src/connection.h b/src/connection.h index 2426a220..ddff03bb 100644 --- a/src/connection.h +++ b/src/connection.h @@ -109,7 +109,7 @@ extern connection_t *new_connection(void) __attribute__ ((__malloc__)); extern void free_connection(connection_t *); extern void connection_add(connection_t *); extern void connection_del(connection_t *); -extern void dump_connections(void); +extern int dump_connections(struct evbuffer *); extern bool read_connection_config(connection_t *); #endif /* __TINC_CONNECTION_H__ */ diff --git a/src/control.c b/src/control.c index 7b27f69a..19ac37a4 100644 --- a/src/control.c +++ b/src/control.c @@ -62,11 +62,41 @@ static void handle_control_data(struct bufferevent *event, void *data) { } if(req.type == REQ_STOP) { - logger(LOG_NOTICE, _("Got stop command")); + logger(LOG_NOTICE, _("Got '%s' command"), "stop"); event_loopexit(NULL); goto respond; } + if(req.type == REQ_DUMP_NODES) { + logger(LOG_NOTICE, _("Got '%s' command"), "dump nodes"); + res.res_errno = dump_nodes(res_data); + goto respond; + } + + if(req.type == REQ_DUMP_EDGES) { + logger(LOG_NOTICE, _("Got '%s' command"), "dump edges"); + res.res_errno = dump_edges(res_data); + goto respond; + } + + if(req.type == REQ_DUMP_SUBNETS) { + logger(LOG_NOTICE, _("Got '%s' command"), "dump subnets"); + res.res_errno = dump_subnets(res_data); + goto respond; + } + + if(req.type == REQ_DUMP_CONNECTIONS) { + logger(LOG_NOTICE, _("Got '%s' command"), "dump connections"); + res.res_errno = dump_connections(res_data); + goto respond; + } + + if(req.type == REQ_DUMP_GRAPH) { + logger(LOG_NOTICE, _("Got '%s' command"), "dump graph"); + res.res_errno = dump_graph(res_data); + goto respond; + } + logger(LOG_DEBUG, _("Malformed control command received")); res.res_errno = EINVAL; diff --git a/src/control_common.h b/src/control_common.h index 3fa034eb..750098e3 100644 --- a/src/control_common.h +++ b/src/control_common.h @@ -26,6 +26,11 @@ enum request_type { REQ_STOP, REQ_RELOAD, REQ_RESTART, + REQ_DUMP_NODES, + REQ_DUMP_EDGES, + REQ_DUMP_SUBNETS, + REQ_DUMP_CONNECTIONS, + REQ_DUMP_GRAPH, }; #define TINC_CTL_VERSION_CURRENT 0 diff --git a/src/edge.c b/src/edge.c index 861b9453..3b584f39 100644 --- a/src/edge.c +++ b/src/edge.c @@ -125,7 +125,7 @@ edge_t *lookup_edge(node_t *from, node_t *to) { return splay_search(from->edge_tree, &v); } -void dump_edges(void) { +int dump_edges(struct evbuffer *out) { splay_node_t *node, *node2; node_t *n; edge_t *e; @@ -133,18 +133,21 @@ void dump_edges(void) { cp(); - logger(LOG_DEBUG, _("Edges:")); - for(node = node_tree->head; node; node = node->next) { n = node->data; for(node2 = n->edge_tree->head; node2; node2 = node2->next) { e = node2->data; address = sockaddr2hostname(&e->address); - logger(LOG_DEBUG, _(" %s to %s at %s options %lx weight %d"), - e->from->name, e->to->name, address, e->options, e->weight); + if(evbuffer_add_printf(out, + _(" %s to %s at %s options %lx weight %d\n"), + e->from->name, e->to->name, address, + e->options, e->weight) == -1) { + free(address); + return errno; + } free(address); } } - logger(LOG_DEBUG, _("End of edges.")); + return 0; } diff --git a/src/edge.h b/src/edge.h index 082ea5dd..dd3d6704 100644 --- a/src/edge.h +++ b/src/edge.h @@ -51,6 +51,6 @@ extern void free_edge_tree(splay_tree_t *); extern void edge_add(edge_t *); extern void edge_del(edge_t *); extern edge_t *lookup_edge(struct node_t *, struct node_t *); -extern void dump_edges(void); +extern int dump_edges(struct evbuffer *); #endif /* __TINC_EDGE_H__ */ diff --git a/src/graph.c b/src/graph.c index 5bf6361e..e6d70afa 100644 --- a/src/graph.c +++ b/src/graph.c @@ -313,66 +313,37 @@ void sssp_bfs(void) { dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true */ -static void dump_graph(int fd, short events, void *data) { +int dump_graph(struct evbuffer *out) { splay_node_t *node; node_t *n; edge_t *e; - char *filename = NULL, *tmpname = NULL; - FILE *file; - - if(!get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename)) - return; - ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph"); - - if(filename[0] == '|') { - file = popen(filename + 1, "w"); - } else { - asprintf(&tmpname, "%s.new", filename); - file = fopen(tmpname, "w"); - } - - if(!file) { - logger(LOG_ERR, "Unable to open graph dump file %s: %s", filename, strerror(errno)); - free(tmpname); - return; - } - - fprintf(file, "digraph {\n"); + if(evbuffer_add_printf(out, "digraph {\n") == -1) + return errno; /* dump all nodes first */ for(node = node_tree->head; node; node = node->next) { n = node->data; - fprintf(file, " %s [label = \"%s\"];\n", n->name, n->name); + if(evbuffer_add_printf(out, " %s [label = \"%s\"];\n", + n->name, n->name) == -1) + return errno; } /* now dump all edges */ for(node = edge_weight_tree->head; node; node = node->next) { e = node->data; - fprintf(file, " %s -> %s;\n", e->from->name, e->to->name); + if(evbuffer_add_printf(out, " %s -> %s;\n", + e->from->name, e->to->name) == -1) + return errno; } - fprintf(file, "}\n"); - - if(filename[0] == '|') { - pclose(file); - } else { - fclose(file); -#ifdef HAVE_MINGW - unlink(filename); -#endif - rename(tmpname, filename); - free(tmpname); - } + if(evbuffer_add_printf(out, "}\n") == -1) + return errno; + + return 0; } void graph(void) { - static struct event ev; - sssp_bfs(); mst_kruskal(); - - if(!timeout_initialized(&ev)) - timeout_set(&ev, dump_graph, NULL); - event_add(&ev, &(struct timeval){5, 0}); } diff --git a/src/graph.h b/src/graph.h index 0d5be20c..88de9f6a 100644 --- a/src/graph.h +++ b/src/graph.h @@ -26,6 +26,6 @@ extern void graph(void); extern void mst_kruskal(void); extern void sssp_bfs(void); -extern void dump_graph(void); +extern int dump_graph(struct evbuffer *); #endif /* __TINC_GRAPH_H__ */ diff --git a/src/net.c b/src/net.c index a4bff6d9..1be4ed84 100644 --- a/src/net.c +++ b/src/net.c @@ -252,19 +252,6 @@ static void sigint_handler(int signal, short events, void *data) { } } -static void sigusr1_handler(int signal, short events, void *data) { - logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal)); - dump_connections(); -} - -static void sigusr2_handler(int signal, short events, void *data) { - logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal)); - dump_device_stats(); - dump_nodes(); - dump_edges(); - dump_subnets(); -} - static void sigwinch_handler(int signal, short events, void *data) { logger(LOG_NOTICE, _("Got %s signal"), strsignal(signal)); purge(); @@ -346,8 +333,6 @@ int main_loop(void) { struct event sigint_event; struct event sigterm_event; struct event sigquit_event; - struct event sigusr1_event; - struct event sigusr2_event; struct event sigwinch_event; struct event sigalrm_event; @@ -363,10 +348,6 @@ int main_loop(void) { signal_add(&sigterm_event, NULL); signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL); signal_add(&sigquit_event, NULL); - signal_set(&sigusr1_event, SIGUSR1, sigusr1_handler, NULL); - signal_add(&sigusr1_event, NULL); - signal_set(&sigusr2_event, SIGUSR2, sigusr2_handler, NULL); - signal_add(&sigusr2_event, NULL); signal_set(&sigwinch_event, SIGWINCH, sigwinch_handler, NULL); signal_add(&sigwinch_event, NULL); signal_set(&sigalrm_event, SIGALRM, sigalrm_handler, NULL); @@ -381,8 +362,6 @@ int main_loop(void) { signal_del(&sigint_event); signal_del(&sigterm_event); signal_del(&sigquit_event); - signal_del(&sigusr1_event); - signal_del(&sigusr2_event); signal_del(&sigwinch_event); signal_del(&sigalrm_event); event_del(&timeout_event); diff --git a/src/node.c b/src/node.c index cbafe712..0960ca76 100644 --- a/src/node.c +++ b/src/node.c @@ -160,22 +160,21 @@ node_t *lookup_node_udp(const sockaddr_t *sa) { return splay_search(node_udp_tree, &n); } -void dump_nodes(void) { +int dump_nodes(struct evbuffer *out) { splay_node_t *node; node_t *n; cp(); - logger(LOG_DEBUG, _("Nodes:")); - for(node = node_tree->head; node; node = node->next) { n = node->data; - logger(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)"), + if(evbuffer_add_printf(out, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s pmtu %d (min %d max %d)\n"), n->name, n->hostname, n->cipher ? n->cipher->nid : 0, n->digest ? n->digest->type : 0, n->maclength, n->compression, n->options, *(uint32_t *)&n->status, n->nexthop ? n->nexthop->name : "-", - n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu); + n->via ? n->via->name : "-", n->mtu, n->minmtu, n->maxmtu) == -1) + return errno; } - logger(LOG_DEBUG, _("End of nodes.")); + return 0; } diff --git a/src/node.h b/src/node.h index 83af5e3c..0476cdb0 100644 --- a/src/node.h +++ b/src/node.h @@ -94,6 +94,6 @@ extern void node_add(node_t *); extern void node_del(node_t *); extern node_t *lookup_node(char *); extern node_t *lookup_node_udp(const sockaddr_t *); -extern void dump_nodes(void); +extern int dump_nodes(struct evbuffer *); #endif /* __TINC_NODE_H__ */ diff --git a/src/subnet.c b/src/subnet.c index bbf4eddd..9d84ec2b 100644 --- a/src/subnet.c +++ b/src/subnet.c @@ -438,7 +438,7 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) { } } -void dump_subnets(void) +int dump_subnets(struct evbuffer *out) { char netstr[MAXNETSTR]; subnet_t *subnet; @@ -446,14 +446,14 @@ void dump_subnets(void) cp(); - logger(LOG_DEBUG, _("Subnet list:")); - for(node = subnet_tree->head; node; node = node->next) { subnet = node->data; if(!net2str(netstr, sizeof netstr, subnet)) continue; - logger(LOG_DEBUG, _(" %s owner %s"), netstr, subnet->owner->name); + if(evbuffer_add_printf(out, _(" %s owner %s\n"), + netstr, subnet->owner->name) == -1) + return errno; } - logger(LOG_DEBUG, _("End of subnet list.")); + return 0; } diff --git a/src/subnet.h b/src/subnet.h index f73aaf95..48eec520 100644 --- a/src/subnet.h +++ b/src/subnet.h @@ -81,6 +81,6 @@ extern subnet_t *lookup_subnet(const struct node_t *, const subnet_t *); extern subnet_t *lookup_subnet_mac(const mac_t *); extern subnet_t *lookup_subnet_ipv4(const ipv4_t *); extern subnet_t *lookup_subnet_ipv6(const ipv6_t *); -extern void dump_subnets(void); +extern int dump_subnets(struct evbuffer *); #endif /* __TINC_SUBNET_H__ */ diff --git a/src/tincctl.c b/src/tincctl.c index 3944fa2e..4982e6b2 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -546,6 +546,38 @@ int main(int argc, char *argv[], char *envp[]) { return send_ctl_request_cooked(fd, REQ_RESTART, NULL, 0) != -1; } + if(!strcasecmp(argv[optind], "dump")) { + if (argc < optind + 2) { + fprintf(stderr, _("Not enough arguments.\n")); + usage(true); + return 1; + } + + if(!strcasecmp(argv[optind+1], "nodes")) { + return send_ctl_request_cooked(fd, REQ_DUMP_NODES, NULL, 0) != -1; + } + + if(!strcasecmp(argv[optind+1], "edges")) { + return send_ctl_request_cooked(fd, REQ_DUMP_EDGES, NULL, 0) != -1; + } + + if(!strcasecmp(argv[optind+1], "subnets")) { + return send_ctl_request_cooked(fd, REQ_DUMP_SUBNETS, NULL, 0) != -1; + } + + if(!strcasecmp(argv[optind+1], "connections")) { + return send_ctl_request_cooked(fd, REQ_DUMP_CONNECTIONS, NULL, 0) != -1; + } + + if(!strcasecmp(argv[optind+1], "graph")) { + return send_ctl_request_cooked(fd, REQ_DUMP_GRAPH, NULL, 0) != -1; + } + + fprintf(stderr, _("Unknown dump type '%s'.\n"), argv[optind+1]); + usage(true); + return 1; + } + fprintf(stderr, _("Unknown command `%s'.\n"), argv[optind]); usage(true); -- 2.20.1