This allows tincctl info to show since when a node is online or offline.
e->to->options = e->options;
e->to->distance = n->distance + 1;
e->to->options = e->options;
e->to->distance = n->distance + 1;
- if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
+ if(!e->to->status.reachable || (e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
+)
update_node_udp(e->to, &e->address);
list_insert_tail(todo_list, e->to);
update_node_udp(e->to, &e->address);
list_insert_tail(todo_list, e->to);
if(n->status.visited != n->status.reachable) {
n->status.reachable = !n->status.reachable;
if(n->status.visited != n->status.reachable) {
n->status.reachable = !n->status.reachable;
+ n->last_state_change = time(NULL);
if(n->status.reachable) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",
if(n->status.reachable) {
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",
short int pmtu, minmtu, maxmtu;
unsigned int options;
node_status_t status;
short int pmtu, minmtu, maxmtu;
unsigned int options;
node_status_t status;
+ long int last_state_change;
while(recvline(fd, line, sizeof line)) {
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);
+ 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) %ld", &code, &req, node, host, port, &cipher, &digest, &maclength, &compression, &options, (unsigned *)&status, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
- 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);
+ 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) %ld", &code, &req, node, host, &cipher, &digest, &maclength, &compression, &options, (unsigned *)&status, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
fprintf(stderr, "Unable to parse node dump from tincd.\n");
return 1;
}
fprintf(stderr, "Unable to parse node dump from tincd.\n");
return 1;
}
printf("Node: %s\n", item);
if(*port)
printf("Address: %s port %s\n", host, port);
printf("Node: %s\n", item);
if(*port)
printf("Address: %s port %s\n", host, port);
+
+ char timestr[32] = "never";
+ if(last_state_change)
+ strftime(timestr, sizeof timestr, "%Y-%m-%d %H:%M:%S", localtime(&last_state_change));
+
+ if(status.reachable)
+ printf("Online since: %s\n", timestr);
+ else
+ printf("Last seen: %s\n", timestr);
+
printf("Status: ");
if(status.validkey)
printf(" validkey");
printf("Status: ");
if(status.validkey)
printf(" validkey");
if(status.sptps)
printf(" sptps");
printf("\n");
if(status.sptps)
printf(" sptps");
printf("\n");
printf("Options: ");
if(options & OPTION_INDIRECT)
printf(" indirect");
printf("Options: ");
if(options & OPTION_INDIRECT)
printf(" indirect");
printf("\n");
printf("Protocol: %d.%d\n", PROT_MAJOR, OPTION_VERSION(options));
printf("Reachability: ");
printf("\n");
printf("Protocol: %d.%d\n", PROT_MAJOR, OPTION_VERSION(options));
printf("Reachability: ");
+ if(!strcmp(host, "MYSELF"))
printf("can reach itself\n");
else if(!status.reachable)
printf("unreachable\n");
printf("can reach itself\n");
else if(!status.reachable)
printf("unreachable\n");
for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data;
for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data;
+ if(!e->to->status.reachable || e->to == myself)
continue;
if(sockaddrcmp_noport(from, &e->address)) {
continue;
if(sockaddrcmp_noport(from, &e->address)) {
myself->nexthop = myself;
myself->via = myself;
myself->status.reachable = true;
myself->nexthop = myself;
myself->via = myself;
myself->status.reachable = true;
+ myself->last_state_change = time(NULL);
myself->status.sptps = experimental;
node_add(myself);
myself->status.sptps = experimental;
node_add(myself);
- if(n->hostname)
- free(n->hostname);
-
hash_insert(node_udp_cache, &n->address, NULL);
if(sa) {
n->address = *sa;
hash_insert(node_udp_cache, sa, n);
hash_insert(node_udp_cache, &n->address, NULL);
if(sa) {
n->address = *sa;
hash_insert(node_udp_cache, sa, n);
n->hostname = sockaddr2hostname(&n->address);
logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
n->hostname = sockaddr2hostname(&n->address);
logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
- } else {
- memset(&n->address, 0, sizeof n->address);
- n->hostname = NULL;
- logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s cleared", n->name);
for(node = node_tree->head; node; node = node->next) {
n = node->data;
for(node = node_tree->head; node; node = node->next) {
n = node->data;
- send_request(c, "%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)", CONTROL, REQ_DUMP_NODES,
+ send_request(c, "%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) %ld", CONTROL, REQ_DUMP_NODES,
n->name, n->hostname, cipher_get_nid(&n->outcipher),
digest_get_nid(&n->outdigest), (int)digest_length(&n->outdigest), n->outcompression,
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
n->name, n->hostname, cipher_get_nid(&n->outcipher),
digest_get_nid(&n->outdigest), (int)digest_length(&n->outdigest), n->outcompression,
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
- n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu);
+ n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
}
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
}
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
char *hostname; /* the hostname of its real ip */
node_status_t status;
char *hostname; /* the hostname of its real ip */
node_status_t status;
+ time_t last_state_change;
time_t last_req_key;
ecdsa_t ecdsa; /* His public ECDSA key */
time_t last_req_key;
ecdsa_t ecdsa; /* His public ECDSA key */