version 1.1, 2019/10/21 14:25:31
|
version 1.1.1.3, 2023/09/27 11:18:58
|
Line 11
|
Line 11
|
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 |
along with this program; if not, write to the Free Software | with this program; if not, write to the Free Software Foundation, Inc., |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
*/ |
*/ |
|
|
#include "config.h" |
#include "config.h" |
Line 26
|
Line 26
|
#include <string.h> |
#include <string.h> |
#include <strings.h> |
#include <strings.h> |
#include <time.h> |
#include <time.h> |
|
#ifdef HAVE_JANSSON |
|
#include <jansson.h> |
|
#endif |
|
#ifdef HAVE_ERROR_H |
|
#include <error.h> |
|
#else |
|
#include "portability/error.h" |
|
#endif |
|
|
#include "mtr.h" |
#include "mtr.h" |
#include "report.h" |
#include "report.h" |
Line 35
|
Line 43
|
#include "utils.h" |
#include "utils.h" |
|
|
#define MAXLOADBAL 5 |
#define MAXLOADBAL 5 |
#define MAX_FORMAT_STR 81 | #define MAX_FORMAT_STR 320 |
|
|
|
|
void report_open( |
void report_open( |
Line 57 static size_t snprint_addr(
|
Line 65 static size_t snprint_addr(
|
struct hostent *host = |
struct hostent *host = |
ctl->dns ? addr2host((void *) addr, ctl->af) : NULL; |
ctl->dns ? addr2host((void *) addr, ctl->af) : NULL; |
if (!host) |
if (!host) |
return snprintf(dst, dst_len, "%s", strlongip(ctl, addr)); | return snprintf(dst, dst_len, "%s", strlongip(ctl->af, addr)); |
else if (ctl->dns && ctl->show_ips) |
else if (ctl->dns && ctl->show_ips) |
return snprintf(dst, dst_len, "%s (%s)", host->h_name, |
return snprintf(dst, dst_len, "%s (%s)", host->h_name, |
strlongip(ctl, addr)); | strlongip(ctl->af, addr)); |
else |
else |
return snprintf(dst, dst_len, "%s", host->h_name); |
return snprintf(dst, dst_len, "%s", host->h_name); |
} else |
} else |
Line 74 static void print_mpls(
|
Line 82 static void print_mpls(
|
{ |
{ |
int k; |
int k; |
for (k = 0; k < mpls->labels; k++) |
for (k = 0; k < mpls->labels; k++) |
printf(" [MPLS: Lbl %lu Exp %u S %cu TTL %u]\n", | printf(" [MPLS: Lbl %lu TC %u S %cu TTL %u]\n", |
mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]); | mpls->label[k], mpls->tc[k], mpls->s[k], mpls->ttl[k]); |
} |
} |
#endif |
#endif |
|
|
Line 162 void report_close(
|
Line 170 void report_close(
|
if (j < 0) |
if (j < 0) |
continue; |
continue; |
|
|
/* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ | /* 1000.0 is a temporary hack for stats usec to ms, impacted net_loss. */ |
if (strchr(data_fields[j].format, 'f')) { |
if (strchr(data_fields[j].format, 'f')) { |
snprintf(buf + len, sizeof(buf), data_fields[j].format, |
snprintf(buf + len, sizeof(buf), data_fields[j].format, |
data_fields[j].net_xxx(at) / 1000.0); |
data_fields[j].net_xxx(at) / 1000.0); |
Line 176 void report_close(
|
Line 184 void report_close(
|
|
|
/* This feature shows 'loadbalances' on routes */ |
/* This feature shows 'loadbalances' on routes */ |
|
|
/* z is starting at 1 because addrs[0] is the same that addr */ | /* Print list of all hosts that have responded from ttl = at + 1 away */ |
for (z = 1; z < MAXPATH; z++) { | for (z = 0; z < MAX_PATH; z++) { |
int found = 0; |
int found = 0; |
addr2 = net_addrs(at, z); |
addr2 = net_addrs(at, z); |
mplss = net_mplss(at, z); |
mplss = net_mplss(at, z); |
if ((addrcmp |
if ((addrcmp |
((void *) &ctl->unspec_addr, (void *) addr2, |
((void *) &ctl->unspec_addr, (void *) addr2, |
ctl->af)) == 0) | ctl->af)) == 0) { |
break; |
break; |
|
} else if ((addrcmp |
|
((void *) addr, (void *) addr2, |
|
ctl->af)) == 0) { |
|
continue; /* Latest Host is already printed */ |
|
} else { |
|
snprint_addr(ctl, name, sizeof(name), addr2); |
|
snprintf(fmt, sizeof(fmt), " %%-%zus", len_hosts); |
|
snprintf(buf, sizeof(buf), fmt, name); |
|
printf("%s\n", buf); |
|
} |
for (w = 0; w < z; w++) |
for (w = 0; w < z; w++) |
/* Ok... checking if there are ips repeated on same hop */ |
/* Ok... checking if there are ips repeated on same hop */ |
if ((addrcmp |
if ((addrcmp |
Line 197 void report_close(
|
Line 215 void report_close(
|
if (!found) { |
if (!found) { |
|
|
#ifdef HAVE_IPINFO |
#ifdef HAVE_IPINFO |
|
if (mpls->labels && z == 1 && ctl->enablempls) |
|
print_mpls(mpls); |
if (is_printii(ctl)) { |
if (is_printii(ctl)) { |
if (mpls->labels && z == 1 && ctl->enablempls) |
|
print_mpls(mpls); |
|
snprint_addr(ctl, name, sizeof(name), addr2); |
snprint_addr(ctl, name, sizeof(name), addr2); |
printf(" %s%s\n", fmt_ipinfo(ctl, addr2), name); |
printf(" %s%s\n", fmt_ipinfo(ctl, addr2), name); |
if (ctl->enablempls) |
|
print_mpls(mplss); |
|
} |
} |
|
if (ctl->enablempls) |
|
print_mpls(mplss); |
#else |
#else |
int k; |
int k; |
if (mpls->labels && z == 1 && ctl->enablempls) { |
if (mpls->labels && z == 1 && ctl->enablempls) { |
for (k = 0; k < mpls->labels; k++) { |
for (k = 0; k < mpls->labels; k++) { |
printf |
printf |
(" | |+-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", | (" | |+-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n", |
mpls->label[k], mpls->exp[k], mpls->s[k], | mpls->label[k], mpls->tc[k], mpls->s[k], |
mpls->ttl[k]); |
mpls->ttl[k]); |
} |
} |
} |
} |
|
|
if (z == 1) { |
if (z == 1) { |
printf(" | `|-- %s\n", strlongip(ctl, addr2)); | printf(" | `|-- %s\n", strlongip(ctl->af, addr2)); |
for (k = 0; k < mplss->labels && ctl->enablempls; k++) { |
for (k = 0; k < mplss->labels && ctl->enablempls; k++) { |
printf |
printf |
(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", | (" | +-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n", |
mplss->label[k], mplss->exp[k], mplss->s[k], | mplss->label[k], mplss->tc[k], mplss->s[k], |
mplss->ttl[k]); |
mplss->ttl[k]); |
} |
} |
} else { |
} else { |
printf(" | |-- %s\n", strlongip(ctl, addr2)); | printf(" | |-- %s\n", strlongip(ctl->af, addr2)); |
for (k = 0; k < mplss->labels && ctl->enablempls; k++) { |
for (k = 0; k < mplss->labels && ctl->enablempls; k++) { |
printf |
printf |
(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", | (" | +-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n", |
mplss->label[k], mplss->exp[k], mplss->s[k], | mplss->label[k], mplss->tc[k], mplss->s[k], |
mplss->ttl[k]); |
mplss->ttl[k]); |
} |
} |
} |
} |
Line 247 void report_close(
|
Line 265 void report_close(
|
if (mpls->labels && z == 1 && ctl->enablempls) { |
if (mpls->labels && z == 1 && ctl->enablempls) { |
int k; |
int k; |
for (k = 0; k < mpls->labels; k++) { |
for (k = 0; k < mpls->labels; k++) { |
printf(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", | printf(" | +-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n", |
mpls->label[k], mpls->exp[k], mpls->s[k], | mpls->label[k], mpls->tc[k], mpls->s[k], |
mpls->ttl[k]); |
mpls->ttl[k]); |
} |
} |
} |
} |
Line 269 void txt_close(
|
Line 287 void txt_close(
|
report_close(ctl); |
report_close(ctl); |
} |
} |
|
|
| #ifdef HAVE_JANSSON |
void json_open( |
void json_open( |
void) |
void) |
{ |
{ |
} |
} |
|
|
| void json_close(struct mtr_ctl *ctl) |
void json_close( | |
struct mtr_ctl *ctl) | |
{ |
{ |
int i, j, at, first, max; | int i, j, at, max; |
| int ret; |
| char buf[128]; |
| json_t *jreport, *jmtr, *jhubs, *jh; |
ip_t *addr; |
ip_t *addr; |
char name[MAX_FORMAT_STR]; |
char name[MAX_FORMAT_STR]; |
|
|
printf("{\n"); | jmtr = json_pack("{ss ss si si}", |
printf(" \"report\": {\n"); | "src", ctl->LocalHostname, |
printf(" \"mtr\": {\n"); | "dst", ctl->Hostname, |
printf(" \"src\": \"%s\",\n", ctl->LocalHostname); | "tos", ctl->tos, |
printf(" \"dst\": \"%s\",\n", ctl->Hostname); | "tests", ctl->MaxPing); |
printf(" \"tos\": \"0x%X\",\n", ctl->tos); | if (!jmtr) |
| goto on_error; |
| |
if (ctl->cpacketsize >= 0) { |
if (ctl->cpacketsize >= 0) { |
printf(" \"psize\": \"%d\",\n", ctl->cpacketsize); | snprintf(buf, sizeof(buf), "%d", ctl->cpacketsize); |
} else { |
} else { |
printf(" \"psize\": \"rand(%d-%d)\",\n", MINPACKET, | snprintf(buf, sizeof(buf), "rand(%d-%d)", MINPACKET, -ctl->cpacketsize); |
-ctl->cpacketsize); | |
} |
} |
|
ret = json_object_set_new(jmtr, "psize", json_string(buf)); |
|
if (ret == -1) |
|
goto on_error; |
|
|
if (ctl->bitpattern >= 0) { |
if (ctl->bitpattern >= 0) { |
printf(" \"bitpattern\": \"0x%02X\",\n", | snprintf(buf, sizeof(buf), "0x%02X", (unsigned char)(ctl->bitpattern)); |
(unsigned char) (ctl->bitpattern)); | |
} else { |
} else { |
printf(" \"bitpattern\": \"rand(0x00-FF)\",\n"); | snprintf(buf, sizeof(buf), "rand(0x00-FF)"); |
} |
} |
printf(" \"tests\": \"%d\"\n", ctl->MaxPing); |
|
printf(" },\n"); |
|
|
|
printf(" \"hubs\": ["); | ret = json_object_set_new(jmtr, "bitpattern", json_string(buf)); |
| if (ret == -1) |
| goto on_error; |
|
|
|
jhubs = json_array(); |
|
if (!jhubs) |
|
goto on_error; |
|
|
max = net_max(ctl); |
max = net_max(ctl); |
at = first = net_min(ctl); | at = net_min(ctl); |
for (; at < max; at++) { |
for (; at < max; at++) { |
addr = net_addr(at); |
addr = net_addr(at); |
snprint_addr(ctl, name, sizeof(name), addr); |
snprint_addr(ctl, name, sizeof(name), addr); |
|
|
if (at == first) { | jh = json_pack("{si ss}", "count", at + 1, "host", name); |
printf("{\n"); | if (!jh) |
} else { | goto on_error; |
printf(" {\n"); | |
} | |
printf(" \"count\": \"%d\",\n", at + 1); | |
printf(" \"host\": \"%s\",\n", name); | |
#ifdef HAVE_IPINFO |
#ifdef HAVE_IPINFO |
if(!ctl->ipinfo_no) { | if (!ctl->ipinfo_no) { |
char* fmtinfo = fmt_ipinfo(ctl, addr); | char* fmtinfo = fmt_ipinfo(ctl, addr); |
if (fmtinfo != NULL) fmtinfo = trim(fmtinfo, '\0'); | if (fmtinfo != NULL) |
printf(" \"ASN\": \"%s\",\n", fmtinfo); | fmtinfo = trim(fmtinfo, '\0'); |
| |
| ret = json_object_set_new(jh, "ASN", json_string(fmtinfo)); |
| if (ret == -1) |
| goto on_error; |
} |
} |
#endif |
#endif |
for (i = 0; i < MAXFLD; i++) { |
|
const char *format; |
|
|
|
|
for (i = 0; i < MAXFLD; i++) { |
j = ctl->fld_index[ctl->fld_active[i]]; |
j = ctl->fld_index[ctl->fld_active[i]]; |
|
|
/* Commas */ |
|
if (i + 1 == MAXFLD) { |
|
printf("\n"); |
|
} else if (j > 0 && i != 0) { |
|
printf(",\n"); |
|
} |
|
|
|
if (j <= 0) |
if (j <= 0) |
continue; /* Field nr 0, " " shouldn't be printed in this method. */ | continue; /* Field nr 0, " " shouldn't be printed in this method. */ |
|
|
/* Format value */ |
|
format = data_fields[j].format; |
|
if (strchr(format, 'f')) { |
|
format = "%.2f"; |
|
} else { |
|
format = "%d"; |
|
} |
|
|
|
/* Format json line */ |
|
snprintf(name, sizeof(name), "%s%s", " \"%s\": ", format); |
|
|
|
/* Output json line */ |
|
if (strchr(data_fields[j].format, 'f')) { |
if (strchr(data_fields[j].format, 'f')) { |
/* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ | ret = json_object_set_new( |
printf(name, | jh, data_fields[j].title, |
data_fields[j].title, | json_real(data_fields[j].net_xxx(at) / 1000.0)); |
data_fields[j].net_xxx(at) / 1000.0); | |
} else { |
} else { |
printf(name, | ret = json_object_set_new( |
data_fields[j].title, data_fields[j].net_xxx(at)); | jh, data_fields[j].title, |
| json_integer(data_fields[j].net_xxx(at))); |
} |
} |
|
if (ret == -1) |
|
goto on_error; |
} |
} |
if (at + 1 == max) { | |
printf(" }]\n"); | ret = json_array_append_new(jhubs, jh); |
} else { | if (ret == -1) |
printf(" },\n"); | goto on_error; |
} | |
} |
} |
printf(" }\n"); |
|
printf("}\n"); |
|
} |
|
|
|
|
jreport = json_pack("{s{so so}}", "report", "mtr", jmtr, "hubs", jhubs); |
|
|
|
ret = json_dumpf(jreport, stdout, JSON_INDENT(4) | JSON_REAL_PRECISION(5)); |
|
if (ret == -1) |
|
goto on_error; |
|
|
|
printf("\n"); // bash prompt should be on new line |
|
json_decref(jreport); |
|
return; |
|
on_error: |
|
error(EXIT_FAILURE, 0, "json_close failed"); |
|
} |
|
#endif |
|
|
|
|
void xml_open( |
void xml_open( |
void) |
void) |
{ |
{ |
Line 428 void xml_close(
|
Line 447 void xml_close(
|
title = "Loss"; |
title = "Loss"; |
} |
} |
|
|
/* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ | /* 1000.0 is a temporary hack for stats usec to ms, impacted net_loss. */ |
if (strchr(data_fields[j].format, 'f')) { |
if (strchr(data_fields[j].format, 'f')) { |
printf(name, |
printf(name, |
title, data_fields[j].net_xxx(at) / 1000.0, title); |
title, data_fields[j].net_xxx(at) / 1000.0, title); |
Line 451 void csv_close(
|
Line 470 void csv_close(
|
struct mtr_ctl *ctl, |
struct mtr_ctl *ctl, |
time_t now) |
time_t now) |
{ |
{ |
int i, j, at, max; | int i, j, at, max, z, w; |
ip_t *addr; |
ip_t *addr; |
|
ip_t *addr2 = NULL; |
char name[MAX_FORMAT_STR]; |
char name[MAX_FORMAT_STR]; |
|
|
for (i = 0; i < MAXFLD; i++) { |
for (i = 0; i < MAXFLD; i++) { |
Line 499 void csv_close(
|
Line 519 void csv_close(
|
if (j < 0) |
if (j < 0) |
continue; |
continue; |
|
|
/* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ | /* 1000.0 is a temporary hack for stats usec to ms, impacted net_loss. */ |
if (strchr(data_fields[j].format, 'f')) { |
if (strchr(data_fields[j].format, 'f')) { |
printf(",%.2f", |
printf(",%.2f", |
(double) (data_fields[j].net_xxx(at) / 1000.0)); |
(double) (data_fields[j].net_xxx(at) / 1000.0)); |
Line 508 void csv_close(
|
Line 528 void csv_close(
|
} |
} |
} |
} |
printf("\n"); |
printf("\n"); |
|
if (ctl->reportwide == 0) |
|
continue; |
|
|
|
for (z = 0; z < MAX_PATH; z++) { |
|
int found = 0; |
|
addr2 = net_addrs(at, z); |
|
snprint_addr(ctl, name, sizeof(name), addr2); |
|
if ((addrcmp |
|
((void *) &ctl->unspec_addr, (void *) addr2, |
|
ctl->af)) == 0) { |
|
break; |
|
} else if ((addrcmp |
|
((void *) addr, (void *) addr2, |
|
ctl->af)) == 0) { |
|
continue; /* Latest Host is already printed */ |
|
} else { |
|
for (w = 0; w < z; w++) |
|
/* Ok... checking if there are ips repeated on same hop */ |
|
if ((addrcmp |
|
((void *) addr2, (void *) net_addrs(at, w), |
|
ctl->af)) == 0) { |
|
found = 1; |
|
break; |
|
} |
|
|
|
if (!found) { |
|
#ifdef HAVE_IPINFO |
|
if (!ctl->ipinfo_no) { |
|
char *fmtinfo = fmt_ipinfo(ctl, addr2); |
|
fmtinfo = trim(fmtinfo, '\0'); |
|
printf("MTR.%s,%lld,%s,%s,%d,%s,%s", PACKAGE_VERSION, |
|
(long long) now, "OK", ctl->Hostname, at + 1, name, |
|
fmtinfo); |
|
} else |
|
#endif |
|
printf("MTR.%s,%lld,%s,%s,%d,%s", PACKAGE_VERSION, |
|
(long long) now, "OK", ctl->Hostname, at + 1, name); |
|
|
|
/* Use values associated with the first ip discovered for this hop */ |
|
for (i = 0; i < MAXFLD; i++) { |
|
j = ctl->fld_index[ctl->fld_active[i]]; |
|
if (j < 0) |
|
continue; |
|
|
|
/* 1000.0 is a temporary hack for stats usec to ms, impacted net_loss. */ |
|
if (strchr(data_fields[j].format, 'f')) { |
|
printf(",%.2f", |
|
(double) (data_fields[j].net_xxx(at) / 1000.0)); |
|
} else { |
|
printf(",%d", data_fields[j].net_xxx(at)); |
|
} |
|
} |
|
printf("\n"); |
|
} |
|
} |
|
} |
} |
} |
} |
} |