"tincctl info" gives more human readable information about nodes or subnets.

This commit is contained in:
Guus Sliepen 2012-07-16 01:05:25 +02:00
parent 3c7003893f
commit 53735a9d96
6 changed files with 298 additions and 1 deletions

View file

@ -2098,6 +2098,10 @@ Dump a list of all meta connections with ourself.
@item dump graph @item dump graph
Dump a graph of the VPN in dotty format. Dump a graph of the VPN in dotty format.
@item info @var{node} | @var{subnet} | @var{address}
Show information about a particular @var{node}, @var{subnet} or @var{address}.
If an @var{address} is given, any matching subnet will be shown.
@item purge @item purge
Purges all information remembered about unreachable nodes. Purges all information remembered about unreachable nodes.

View file

@ -101,6 +101,7 @@ If
is omitted, the default length will be 2048 bits. is omitted, the default length will be 2048 bits.
When saving keys to existing files, tinc will not delete the old keys; When saving keys to existing files, tinc will not delete the old keys;
you have to remove them manually. you have to remove them manually.
.It dump nodes .It dump nodes
Dump a list of all known nodes in the VPN. Dump a list of all known nodes in the VPN.
.It dump edges .It dump edges
@ -113,6 +114,9 @@ Dump a list of all meta connections with ourself.
Dump a graph of the VPN in Dump a graph of the VPN in
.Xr dotty 1 .Xr dotty 1
format. format.
.It info Ar node | subnet | address
Show information about a particular node, subnet or address.
If an address is given, any matching subnet will be shown.
.It purge .It purge
Purges all information remembered about unreachable nodes. Purges all information remembered about unreachable nodes.
.It debug Ar N .It debug Ar N

View file

@ -24,7 +24,7 @@ nodist_tincd_SOURCES = \
tincctl_SOURCES = \ tincctl_SOURCES = \
utils.c getopt.c getopt1.c dropin.c \ utils.c getopt.c getopt1.c dropin.c \
list.c tincctl.c top.c info.c list.c subnet_parse.c tincctl.c top.c
nodist_tincctl_SOURCES = \ nodist_tincctl_SOURCES = \
ecdsagen.c rsagen.c ecdsagen.c rsagen.c

248
src/info.c Normal file
View file

@ -0,0 +1,248 @@
/*
info.c -- Show information about a node, subnet or address
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "system.h"
#include "control_common.h"
#include "list.h"
#include "subnet.h"
#include "tincctl.h"
#include "info.h"
#include "xalloc.h"
void logger(int level, int priority, const char *format, ...) {
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
}
static int info_node(int fd, const char *item) {
// Check the list of nodes
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_NODES, item);
bool found = false;
char line[4096];
char node[4096];
char from[4096];
char to[4096];
char subnet[4096];
char host[4096];
char port[4096];
char via[4096];
char nexthop[4096];
int code, req, cipher, digest, maclength, compression, distance;
short int pmtu, minmtu, maxmtu;
unsigned int options;
node_status_t status;
while(recvline(fd, line, sizeof line)) {
int n = sscanf(line, "%d %d %s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)", &code, &req, node, host, port, &cipher, &digest, &maclength, &compression, &options, (unsigned *)&status, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu);
if(n == 2)
break;
if(n != 17) {
*port = 0;
n = sscanf(line, "%d %d %s at %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)", &code, &req, node, host, &cipher, &digest, &maclength, &compression, &options, (unsigned *)&status, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu);
if(n != 16) {
fprintf(stderr, "Unable to parse node dump from tincd.\n");
return 1;
}
}
if(!strcmp(node, item)) {
found = true;
break;
}
}
if(!found) {
fprintf(stderr, "Unknown node %s.\n", item);
return 1;
}
while(recvline(fd, line, sizeof line)) {
if(sscanf(line, "%d %d %s", &code, &req, node) == 2)
break;
}
printf("Node: %s\n", item);
if(*port)
printf("Address: %s port %s\n", host, port);
printf("Status: ");
if(status.validkey)
printf(" validkey");
if(status.visited)
printf(" visited");
if(status.reachable)
printf(" reachable");
if(status.indirect)
printf(" indirect");
if(status.ecdh)
printf(" ecdh");
printf("\n");
printf("Options: ");
if(options & OPTION_INDIRECT)
printf(" indirect");
if(options & OPTION_TCPONLY)
printf(" tcponly");
if(options & OPTION_PMTU_DISCOVERY)
printf(" pmtu_discovery");
if(options & OPTION_CLAMP_MSS)
printf(" clamp_mss");
printf("\n");
printf("Reachability: ");
if(!*port)
printf("can reach itself\n");
else if(!status.reachable)
printf("unreachable\n");
else if(strcmp(via, item))
printf("indirectly via %s\n", via);
else if(!status.validkey)
printf("unknown\n");
else if(minmtu > 0)
printf("directly with UDP\nPMTU: %d\n", pmtu);
else if(!strcmp(nexthop, item))
printf("directly with TCP\n");
else
printf("none, forwarded via %s\n", nexthop);
// List edges
printf("Edges: ");
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_EDGES, item);
while(recvline(fd, line, sizeof line)) {
int n = sscanf(line, "%d %d %s to %s", &code, &req, from, to);
if(n == 2)
break;
if(n != 4) {
fprintf(stderr, "Unable to parse edge dump from tincd.\n%s\n", line);
return 1;
}
if(!strcmp(from, item))
printf(" %s", to);
}
printf("\n");
// List subnets
printf("Subnets: ");
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
while(recvline(fd, line, sizeof line)) {
int n = sscanf(line, "%d %d %s owner %s", &code, &req, subnet, from);
if(n == 2)
break;
if(n != 4) {
fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
return 1;
}
if(!strcmp(from, item))
printf(" %s", subnet);
}
printf("\n");
return 0;
}
static int info_subnet(int fd, const char *item) {
subnet_t subnet, find;
if(!str2net(&find, item))
return 1;
bool address = !strchr(item, '/');
bool weight = strchr(item, '#');
bool found = false;
char line[4096];
char netstr[4096];
char owner[4096];
int code, req;
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
while(recvline(fd, line, sizeof line)) {
int n = sscanf(line, "%d %d %s owner %s", &code, &req, netstr, owner);
if(n == 2)
break;
if(n != 4 || !str2net(&subnet, netstr)) {
fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
return 1;
}
if(find.type != subnet.type)
continue;
if(weight) {
if(find.weight != subnet.weight)
continue;
}
if(find.type == SUBNET_IPV4) {
if(address) {
if(maskcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, subnet.net.ipv4.prefixlength))
continue;
} else {
if(find.net.ipv4.prefixlength != subnet.net.ipv4.prefixlength)
continue;
if(memcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, sizeof subnet.net.ipv4))
continue;
}
} else if(find.type == SUBNET_IPV6) {
if(address) {
if(maskcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, subnet.net.ipv6.prefixlength))
continue;
} else {
if(find.net.ipv6.prefixlength != subnet.net.ipv6.prefixlength)
continue;
if(memcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, sizeof subnet.net.ipv6))
continue;
}
} if(find.type == SUBNET_MAC) {
if(memcmp(&find.net.mac.address, &subnet.net.mac.address, sizeof subnet.net.mac))
continue;
}
found = true;
printf("Subnet: %s\n", netstr);
printf("Owner: %s\n", owner);
}
if(!found) {
if(address)
fprintf(stderr, "Unknown address %s.\n", item);
else
fprintf(stderr, "Unknown subnet %s.\n", item);
return 1;
}
return 0;
}
int info(int fd, const char *item) {
if(check_id(item))
return info_node(fd, item);
if(strchr(item, '.') || strchr(item, ':'))
return info_subnet(fd, item);
fprintf(stderr, "Argument is not a node name, subnet or address.\n");
return 1;
}

26
src/info.h Normal file
View file

@ -0,0 +1,26 @@
/*
info.h -- header for info.c.
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
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
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __TINC_INFO_H__
#define __TINC_INFO_H__
extern int info(int fd, const char *item);
#endif

View file

@ -25,6 +25,7 @@
#include "protocol.h" #include "protocol.h"
#include "control_common.h" #include "control_common.h"
#include "ecdsagen.h" #include "ecdsagen.h"
#include "info.h"
#include "rsagen.h" #include "rsagen.h"
#include "utils.h" #include "utils.h"
#include "tincctl.h" #include "tincctl.h"
@ -120,6 +121,7 @@ static void usage(bool status) {
" subnets - all known subnets in the VPN\n" " subnets - all known subnets in the VPN\n"
" connections - all meta connections with ourself\n" " connections - all meta connections with ourself\n"
" graph - graph of the VPN in dotty format\n" " graph - graph of the VPN in dotty format\n"
" info NODE|SUBNET|ADDRESS Give information about a particular NODE, SUBNET or ADDRESS.\n"
" purge Purge unreachable nodes\n" " purge Purge unreachable nodes\n"
" debug N Set debug level\n" " debug N Set debug level\n"
" retry Retry all outgoing connections\n" " retry Retry all outgoing connections\n"
@ -1286,6 +1288,18 @@ static int cmd_version(int argc, char *argv[]) {
return 0; return 0;
} }
static int cmd_info(int argc, char *argv[]) {
if(argc != 2) {
fprintf(stderr, "Invalid number of arguments.\n");
return 1;
}
if(!connect_tincd())
return 1;
return info(fd, argv[1]);
}
static const char *conffiles[] = { static const char *conffiles[] = {
"tinc.conf", "tinc.conf",
"tinc-up", "tinc-up",
@ -1374,6 +1388,7 @@ static const struct {
{"generate-ecdsa-keys", cmd_generate_ecdsa_keys}, {"generate-ecdsa-keys", cmd_generate_ecdsa_keys},
{"help", cmd_help}, {"help", cmd_help},
{"version", cmd_version}, {"version", cmd_version},
{"info", cmd_info},
{"edit", cmd_edit}, {"edit", cmd_edit},
{NULL, NULL}, {NULL, NULL},
}; };