/*
info.c -- Show information about a node, subnet or address
- Copyright (C) 2012-2013 Guus Sliepen <guus@tinc-vpn.org>
+ Copyright (C) 2012-2017 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
#include "system.h"
#include "control_common.h"
-#include "list.h"
#include "subnet.h"
#include "tincctl.h"
#include "info.h"
#include "utils.h"
-#include "xalloc.h"
void logger(int level, int priority, const char *format, ...) {
+ (void)level;
+ (void)priority;
va_list ap;
+
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
+
fputc('\n', stderr);
}
char *strip_weight(char *netstr) {
- int len = strlen(netstr);
- if(len >= 3 && !strcmp(netstr + len - 3, "#10"))
+ size_t len = strlen(netstr);
+
+ if(len >= 3 && !strcmp(netstr + len - 3, "#10")) {
netstr[len - 3] = 0;
+ }
+
return netstr;
}
} status_union;
node_status_t status;
long int last_state_change;
+ int udp_ping_rtt;
+ uint64_t in_packets, in_bytes, out_packets, out_bytes;
- while(recvline(fd, line, sizeof line)) {
- int n = sscanf(line, "%d %d %s %s %s port %s %d %d %d %d %x %"PRIx32" %s %s %d %hd %hd %hd %ld", &code, &req, node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_union.raw, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
+ while(recvline(fd, line, sizeof(line))) {
+ int n = sscanf(line, "%d %d %4095s %4095s %4095s port %4095s %d %d %d %d %x %"PRIx32" %4095s %4095s %d %hd %hd %hd %ld %d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, &code, &req, node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_union.raw, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change, &udp_ping_rtt, &in_packets, &in_bytes, &out_packets, &out_bytes);
- if(n == 2)
+ if(n == 2) {
break;
+ }
- if(n != 19) {
+ if(n != 24) {
fprintf(stderr, "Unable to parse node dump from tincd.\n");
return 1;
}
return 1;
}
- while(recvline(fd, line, sizeof line)) {
- if(sscanf(line, "%d %d %s", &code, &req, node) == 2)
+ while(recvline(fd, line, sizeof(line))) {
+ if(sscanf(line, "%d %d %4095s", &code, &req, node) == 2) {
break;
+ }
}
printf("Node: %s\n", item);
char timestr[32] = "never";
time_t lsc_time = last_state_change;
- if(last_state_change)
- strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&lsc_time));
+ if(last_state_change) {
+ strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&lsc_time));
+ }
status = status_union.bits;
- if(status.reachable)
+ if(status.reachable) {
printf("Online since: %s\n", timestr);
- else
+ } else {
printf("Last seen: %s\n", timestr);
+ }
printf("Status: ");
- if(status.validkey)
+
+ if(status.validkey) {
printf(" validkey");
- if(status.visited)
+ }
+
+ if(status.visited) {
printf(" visited");
- if(status.reachable)
+ }
+
+ if(status.reachable) {
printf(" reachable");
- if(status.indirect)
+ }
+
+ if(status.indirect) {
printf(" indirect");
- if(status.sptps)
+ }
+
+ if(status.sptps) {
printf(" sptps");
- if(status.udp_confirmed)
+ }
+
+ if(status.udp_confirmed) {
printf(" udp_confirmed");
+ }
+
printf("\n");
printf("Options: ");
- if(options & OPTION_INDIRECT)
+
+ if(options & OPTION_INDIRECT) {
printf(" indirect");
- if(options & OPTION_TCPONLY)
+ }
+
+ if(options & OPTION_TCPONLY) {
printf(" tcponly");
- if(options & OPTION_PMTU_DISCOVERY)
+ }
+
+ if(options & OPTION_PMTU_DISCOVERY) {
printf(" pmtu_discovery");
- if(options & OPTION_CLAMP_MSS)
+ }
+
+ if(options & OPTION_CLAMP_MSS) {
printf(" clamp_mss");
+ }
+
printf("\n");
printf("Protocol: %d.%d\n", PROT_MAJOR, OPTION_VERSION(options));
printf("Reachability: ");
- if(!strcmp(host, "MYSELF"))
+
+ if(!strcmp(host, "MYSELF")) {
printf("can reach itself\n");
- else if(!status.reachable)
+ } else if(!status.reachable) {
printf("unreachable\n");
- else if(strcmp(via, item))
+ } else if(strcmp(via, item)) {
printf("indirectly via %s\n", via);
- else if(!status.validkey)
+ } else if(!status.validkey) {
printf("unknown\n");
- else if(minmtu > 0)
+ } else if(minmtu > 0) {
printf("directly with UDP\nPMTU: %d\n", pmtu);
- else if(!strcmp(nexthop, item))
+
+ if(udp_ping_rtt != -1) {
+ printf("RTT: %d.%03d\n", udp_ping_rtt / 1000, udp_ping_rtt % 1000);
+ }
+ } else if(!strcmp(nexthop, item)) {
printf("directly with TCP\n");
- else
+ } else {
printf("none, forwarded via %s\n", nexthop);
+ }
+
+ printf("RX: %"PRIu64" packets %"PRIu64" bytes\n", in_packets, in_bytes);
+ printf("TX: %"PRIu64" packets %"PRIu64" bytes\n", out_packets, out_bytes);
// 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 %s", &code, &req, from, to);
- if(n == 2)
+
+ while(recvline(fd, line, sizeof(line))) {
+ int n = sscanf(line, "%d %d %4095s %4095s", &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))
+
+ 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 %s", &code, &req, subnet, from);
- if(n == 2)
+
+ while(recvline(fd, line, sizeof(line))) {
+ int n = sscanf(line, "%d %d %4095s %4095s", &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))
+
+ if(!strcmp(from, item)) {
printf(" %s", strip_weight(subnet));
+ }
}
+
printf("\n");
return 0;
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 %s", &code, &req, netstr, owner);
- if(n == 2)
+
+ while(recvline(fd, line, sizeof(line))) {
+ int n = sscanf(line, "%d %d %4095s %4095s", &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)
+ if(find.type != subnet.type) {
continue;
+ }
if(weight) {
- if(find.weight != subnet.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))
+ 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)
+ if(find.net.ipv4.prefixlength != subnet.net.ipv4.prefixlength) {
continue;
- if(memcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, sizeof subnet.net.ipv4))
+ }
+
+ 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))
+ 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)
+ if(find.net.ipv6.prefixlength != subnet.net.ipv6.prefixlength) {
continue;
- if(memcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, sizeof subnet.net.ipv6))
+ }
+
+ 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))
+ }
+
+ if(find.type == SUBNET_MAC) {
+ if(memcmp(&find.net.mac.address, &subnet.net.mac.address, sizeof(subnet.net.mac))) {
continue;
+ }
}
found = true;
}
if(!found) {
- if(address)
+ if(address) {
fprintf(stderr, "Unknown address %s.\n", item);
- else
+ } else {
fprintf(stderr, "Unknown subnet %s.\n", item);
+ }
+
return 1;
}
}
int info(int fd, const char *item) {
- if(check_id(item))
+ if(check_id(item)) {
return info_node(fd, item);
- if(strchr(item, '.') || strchr(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;