1 /*
2  * sc_wartsdump
3  *
4  * $Id: sc_wartsdump.c,v 1.233 2021/10/23 04:46:52 mjl Exp $
5  *
6  *        Matthew Luckie
7  *        mjl@luckie.org.nz
8  *
9  * Copyright (C) 2004-2006 Matthew Luckie
10  * Copyright (C) 2006-2011 The University of Waikato
11  * Copyright (C) 2012-2015 The Regents of the University of California
12  * Copyright (C) 2019-2021 Matthew Luckie
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, version 2.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 #include "internal.h"
33 
34 #include "scamper_addr.h"
35 #include "scamper_list.h"
36 #include "scamper_icmpext.h"
37 #include "trace/scamper_trace.h"
38 #include "ping/scamper_ping.h"
39 #include "tracelb/scamper_tracelb.h"
40 #include "dealias/scamper_dealias.h"
41 #include "neighbourdisc/scamper_neighbourdisc.h"
42 #include "tbit/scamper_tbit.h"
43 #include "sting/scamper_sting.h"
44 #include "sniff/scamper_sniff.h"
45 #include "host/scamper_host.h"
46 #include "scamper_file.h"
47 #include "utils.h"
48 
usage()49 static void usage()
50 {
51   fprintf(stderr, "usage: sc_wartsdump <file>\n");
52   return;
53 }
54 
icmp_unreach_tostr(char * buf,size_t len,int at,uint8_t co)55 static char *icmp_unreach_tostr(char *buf, size_t len, int at, uint8_t co)
56 {
57   char *p = NULL;
58 
59   if(at == SCAMPER_ADDR_TYPE_IPV4)
60     {
61       switch(co)
62 	{
63 	case ICMP_UNREACH_NET:           p = "net";           break;
64 	case ICMP_UNREACH_HOST:          p = "host";          break;
65 	case ICMP_UNREACH_PROTOCOL:      p = "protocol";      break;
66 	case ICMP_UNREACH_PORT:          p = "port";          break;
67 	case ICMP_UNREACH_SRCFAIL:       p = "src-rt failed"; break;
68 	case ICMP_UNREACH_NET_UNKNOWN:   p = "net unknown";   break;
69 	case ICMP_UNREACH_HOST_UNKNOWN:  p = "host unknown";  break;
70 	case ICMP_UNREACH_ISOLATED:      p = "isolated";      break;
71 	case ICMP_UNREACH_NET_PROHIB:    p = "net prohib";    break;
72 	case ICMP_UNREACH_HOST_PROHIB:   p = "host prohib";   break;
73 	case ICMP_UNREACH_TOSNET:        p = "tos net";       break;
74 	case ICMP_UNREACH_TOSHOST:       p = "tos host";      break;
75 	case ICMP_UNREACH_FILTER_PROHIB: p = "admin prohib";  break;
76 	case ICMP_UNREACH_NEEDFRAG:      p = "need frag";     break;
77 	}
78     }
79   else
80     {
81       switch(co)
82 	{
83 	case ICMP6_DST_UNREACH_NOROUTE:     p = "no route";     break;
84 	case ICMP6_DST_UNREACH_ADMIN:       p = "admin prohib"; break;
85 	case ICMP6_DST_UNREACH_BEYONDSCOPE: p = "beyond scope"; break;
86 	case ICMP6_DST_UNREACH_ADDR:        p = "addr"; break;
87 	case ICMP6_DST_UNREACH_NOPORT:      p = "port"; break;
88 	}
89     }
90 
91   if(p != NULL)
92     snprintf(buf, len, "%s", p);
93   else
94     snprintf(buf, len, "%d", co);
95 
96   return buf;
97 }
98 
dump_list_summary(scamper_list_t * list)99 static void dump_list_summary(scamper_list_t *list)
100 {
101   if(list != NULL)
102     {
103       printf(" list id: %d", list->id);
104       if(list->name != NULL)
105 	printf(", name: %s", list->name);
106       if(list->monitor != NULL)
107 	printf(", monitor: %s", list->monitor);
108       printf("\n");
109     }
110   return;
111 }
112 
dump_cycle_summary(scamper_cycle_t * cycle)113 static void dump_cycle_summary(scamper_cycle_t *cycle)
114 {
115   if(cycle != NULL)
116     printf(" cycle id: %d\n", cycle->id);
117   return;
118 }
119 
dump_tcp_flags(uint8_t flags)120 static void dump_tcp_flags(uint8_t flags)
121 {
122   if(flags != 0)
123     {
124       printf(" (%s%s%s%s%s%s%s%s )",
125 	     (flags & 0x01) ? " fin" : "",
126 	     (flags & 0x02) ? " syn" : "",
127 	     (flags & 0x04) ? " rst" : "",
128 	     (flags & 0x08) ? " psh" : "",
129 	     (flags & 0x10) ? " ack" : "",
130 	     (flags & 0x20) ? " urg" : "",
131 	     (flags & 0x40) ? " ece" : "",
132 	     (flags & 0x80) ? " cwr" : "");
133     }
134   return;
135 }
136 
dump_timeval(const char * label,struct timeval * start)137 static void dump_timeval(const char *label, struct timeval *start)
138 {
139   time_t tt = start->tv_sec;
140   char buf[32];
141   memcpy(buf, ctime(&tt), 24); buf[24] = '\0';
142   printf(" %s: %s %06d\n", label, buf, (int)start->tv_usec);
143   return;
144 }
145 
dump_trace_hop(const scamper_trace_t * trace,scamper_trace_hop_t * hop)146 static void dump_trace_hop(const scamper_trace_t *trace,
147 			   scamper_trace_hop_t *hop)
148 {
149   struct timeval tv;
150   scamper_icmpext_t *ie;
151   uint32_t u32;
152   char addr[256];
153   int i;
154   char *comma = "";
155 
156   printf("hop %2d  %s",
157 	 hop->hop_probe_ttl,
158 	 scamper_addr_tostr(hop->hop_addr, addr, sizeof(addr)));
159   if(hop->hop_name != NULL)
160     printf(" name %s", hop->hop_name);
161   printf("\n");
162 
163   printf(" attempt: %d", hop->hop_probe_id);
164   if(hop->hop_tx.tv_sec != 0)
165     {
166       timeval_diff_tv(&tv, &trace->start, &hop->hop_tx);
167       printf(", tx: %d.%06ds", (int)tv.tv_sec, (int)tv.tv_usec);
168     }
169   printf(", rtt: %d.%06ds, probe-size: %d\n",
170 	 (int)hop->hop_rtt.tv_sec, (int)hop->hop_rtt.tv_usec,
171 	 hop->hop_probe_size);
172 
173   if(hop->hop_flags & SCAMPER_TRACE_HOP_FLAG_REPLY_TTL)
174     {
175       printf("%s reply-ttl: %d", comma, hop->hop_reply_ttl);
176       comma = ",";
177     }
178 
179   if((trace->flags & SCAMPER_TRACE_FLAG_RXERR) == 0)
180     {
181       printf("%s reply-size: %d", comma, hop->hop_reply_size);
182       comma = ",";
183       if(hop->hop_addr->type == SCAMPER_ADDR_TYPE_IPV4)
184 	printf("%s reply-ipid: 0x%04x", comma, hop->hop_reply_ipid);
185     }
186 
187   if(hop->hop_addr->type == SCAMPER_ADDR_TYPE_IPV4)
188     printf("%s reply-tos 0x%02x", comma, hop->hop_reply_tos);
189 
190   if(comma[0] != '\0')
191     printf("\n");
192 
193   if(SCAMPER_TRACE_HOP_IS_ICMP(hop))
194     {
195       printf(" icmp-type: %d, icmp-code: %d",
196 	     hop->hop_icmp_type, hop->hop_icmp_code);
197       if(SCAMPER_TRACE_HOP_IS_ICMP_Q(hop))
198 	{
199 	  printf(", q-ttl: %d, q-len: %d",
200 		 hop->hop_icmp_q_ttl, hop->hop_icmp_q_ipl);
201 	  if(hop->hop_addr->type == SCAMPER_ADDR_TYPE_IPV4)
202 	    printf(", q-tos %d", hop->hop_icmp_q_tos);
203 	}
204       if(SCAMPER_TRACE_HOP_IS_ICMP_PTB(hop))
205 	printf(", nhmtu: %d", hop->hop_icmp_nhmtu);
206       printf("\n");
207     }
208   else if(SCAMPER_TRACE_HOP_IS_TCP(hop))
209     {
210       printf(" tcp-flags: 0x%02x", hop->hop_tcp_flags);
211       dump_tcp_flags(hop->hop_tcp_flags);
212       printf("\n");
213     }
214 
215   printf(" flags: 0x%02x", hop->hop_flags);
216   if(hop->hop_flags != 0)
217     {
218       printf(" (");
219       if(hop->hop_flags & SCAMPER_TRACE_HOP_FLAG_TS_SOCK_RX)
220 	printf(" sockrxts");
221       if(hop->hop_flags & SCAMPER_TRACE_HOP_FLAG_TS_DL_TX)
222 	printf(" dltxts");
223       if(hop->hop_flags & SCAMPER_TRACE_HOP_FLAG_TS_DL_RX)
224 	printf(" dlrxts");
225       if(hop->hop_flags & SCAMPER_TRACE_HOP_FLAG_TS_TSC)
226 	printf(" tscrtt");
227       if(hop->hop_flags & SCAMPER_TRACE_HOP_FLAG_REPLY_TTL)
228 	printf(" replyttl");
229       printf(" )");
230     }
231   printf("\n");
232 
233   for(ie = hop->hop_icmpext; ie != NULL; ie = ie->ie_next)
234     {
235       if(SCAMPER_ICMPEXT_IS_MPLS(ie))
236 	{
237 	  for(i=0; i<SCAMPER_ICMPEXT_MPLS_COUNT(ie); i++)
238 	    {
239 	      u32 = SCAMPER_ICMPEXT_MPLS_LABEL(ie, i);
240 	      printf("%9s ttl: %d, s: %d, exp: %d, label: %d\n",
241 		     (i == 0) ? "mpls ext" : "",
242 		     SCAMPER_ICMPEXT_MPLS_TTL(ie, i),
243 		     SCAMPER_ICMPEXT_MPLS_S(ie, i),
244 		     SCAMPER_ICMPEXT_MPLS_EXP(ie, i), u32);
245 	    }
246 	}
247     }
248 
249   return;
250 }
251 
dump_trace(scamper_trace_t * trace)252 static void dump_trace(scamper_trace_t *trace)
253 {
254   scamper_trace_hop_t *hop;
255   scamper_trace_pmtud_t *pmtud;
256   scamper_trace_pmtud_n_t *n;
257   uint16_t u16;
258   uint8_t u8;
259   char buf[256];
260   int i;
261 
262   if(trace->src != NULL)
263     {
264       scamper_addr_tostr(trace->src, buf, sizeof(buf));
265       printf("traceroute from %s to ", buf);
266       scamper_addr_tostr(trace->dst, buf, sizeof(buf));
267       printf("%s\n", buf);
268     }
269   else
270     {
271       printf("traceroute to %s\n",
272 	     scamper_addr_tostr(trace->dst, buf, sizeof(buf)));
273     }
274 
275   dump_list_summary(trace->list);
276   dump_cycle_summary(trace->cycle);
277   printf(" user-id: %d\n", trace->userid);
278   if(trace->rtr != NULL)
279     printf(" rtr: %s\n", scamper_addr_tostr(trace->rtr, buf, sizeof(buf)));
280   dump_timeval("start", &trace->start);
281 
282   printf(" type: ");
283   switch(trace->type)
284     {
285     case SCAMPER_TRACE_TYPE_ICMP_ECHO:
286       printf("icmp, echo id: %d", trace->sport);
287       break;
288 
289     case SCAMPER_TRACE_TYPE_ICMP_ECHO_PARIS:
290       /*
291        * if the byte ordering of the trace->sport used in the icmp csum
292        * is unknown -- that is, not known to be correct, print that detail
293        */
294       printf("icmp paris, echo id: %d", trace->sport);
295       if(SCAMPER_TRACE_IS_ICMPCSUMDP(trace))
296 	printf(", csum: 0x%04x", trace->dport);
297       break;
298 
299     case SCAMPER_TRACE_TYPE_UDP:
300       printf("udp, sport: %d, base dport: %d",
301 	     trace->sport, trace->dport);
302       break;
303 
304     case SCAMPER_TRACE_TYPE_UDP_PARIS:
305       printf("udp paris, sport: %d, dport: %d",
306 	     trace->sport, trace->dport);
307       break;
308 
309     case SCAMPER_TRACE_TYPE_TCP:
310       printf("tcp, sport: %d, dport: %d", trace->sport, trace->dport);
311       break;
312 
313     case SCAMPER_TRACE_TYPE_TCP_ACK:
314       printf("tcp-ack, sport: %d, dport: %d",
315 	     trace->sport, trace->dport);
316       break;
317 
318     default:
319       printf("%d", trace->type);
320       break;
321     }
322   if(trace->offset != 0)
323     printf(", offset %d", trace->offset);
324   printf("\n");
325 
326   if(trace->dtree != NULL)
327     {
328       printf(" doubletree firsthop: %d", trace->dtree->firsthop);
329       if(trace->dtree->lss != NULL)
330 	printf(", lss-name: %s", trace->dtree->lss);
331       if(trace->dtree->lss_stop != NULL)
332 	printf(", lss-stop: %s",
333 	       scamper_addr_tostr(trace->dtree->lss_stop, buf, sizeof(buf)));
334       if(trace->dtree->gss_stop != NULL)
335 	printf(", gss-stop: %s",
336 	       scamper_addr_tostr(trace->dtree->gss_stop, buf, sizeof(buf)));
337       printf("\n");
338     }
339 
340   printf(" attempts: %d, hoplimit: %d, loops: %d, probec: %d\n",
341 	 trace->attempts, trace->hoplimit, trace->loops, trace->probec);
342   printf(" squeries: %d, gaplimit: %d, gapaction: ",
343 	 trace->squeries, trace->gaplimit);
344   if(trace->gapaction == SCAMPER_TRACE_GAPACTION_STOP)
345     printf("stop");
346   else if(trace->gapaction == SCAMPER_TRACE_GAPACTION_LASTDITCH)
347     printf("lastditch");
348   else
349     printf("0x%02x", trace->gapaction);
350   printf("\n");
351 
352   printf(" wait-timeout: %ds", trace->wait);
353   if(trace->wait_probe != 0)
354     printf(", wait-probe: %dms", trace->wait_probe * 10);
355   if(trace->confidence != 0)
356     printf(", confidence: %d%%", trace->confidence);
357   printf("\n");
358 
359   printf(" flags: 0x%02x", trace->flags);
360   if(trace->flags != 0)
361     {
362       printf(" (");
363       if(trace->flags & SCAMPER_TRACE_FLAG_ALLATTEMPTS)
364 	printf(" all-attempts");
365       if(trace->flags & SCAMPER_TRACE_FLAG_PMTUD)
366 	printf(" pmtud");
367       if(trace->flags & SCAMPER_TRACE_FLAG_DL)
368 	printf(" dl");
369       if(trace->flags & SCAMPER_TRACE_FLAG_IGNORETTLDST)
370 	printf(" ignorettldst");
371       if(trace->flags & SCAMPER_TRACE_FLAG_DOUBLETREE)
372 	printf(" doubletree");
373       if(trace->flags & SCAMPER_TRACE_FLAG_ICMPCSUMDP)
374 	printf(" icmp-csum-dport");
375       if(trace->flags & SCAMPER_TRACE_FLAG_CONSTPAYLOAD)
376 	printf(" const-payload");
377       if(trace->flags & SCAMPER_TRACE_FLAG_RXERR)
378 	printf(" rxerr");
379       if(trace->flags & SCAMPER_TRACE_FLAG_PTR)
380 	printf(" ptr");
381       printf(" )");
382     }
383   printf("\n");
384 
385   printf(" stop reason: ");
386   switch(trace->stop_reason)
387     {
388     case SCAMPER_TRACE_STOP_NONE:
389       printf("none");
390       break;
391 
392     case SCAMPER_TRACE_STOP_COMPLETED:
393       printf("done");
394       break;
395 
396     case SCAMPER_TRACE_STOP_UNREACH:
397       i = trace->dst->type;
398       printf("icmp unreach %s",
399 	     icmp_unreach_tostr(buf, sizeof(buf), i, trace->stop_data));
400       break;
401 
402     case SCAMPER_TRACE_STOP_ICMP:
403       printf("icmp type %d", trace->stop_data);
404       break;
405 
406     case SCAMPER_TRACE_STOP_LOOP:
407       printf("loop");
408       break;
409 
410     case SCAMPER_TRACE_STOP_GAPLIMIT:
411       printf("gaplimit");
412       break;
413 
414     case SCAMPER_TRACE_STOP_ERROR:
415       printf("errno %d", trace->stop_data);
416       break;
417 
418     case SCAMPER_TRACE_STOP_HOPLIMIT:
419       printf("hoplimit");
420       break;
421 
422     case SCAMPER_TRACE_STOP_GSS:
423       printf("dtree-gss");
424       break;
425 
426     case SCAMPER_TRACE_STOP_HALTED:
427       printf("halted");
428       break;
429 
430     default:
431       printf("reason 0x%02x data 0x%02x",trace->stop_reason,trace->stop_data);
432       break;
433     }
434   printf("\n");
435 
436   for(u16=0; u16<trace->hop_count; u16++)
437     for(hop = trace->hops[u16]; hop != NULL; hop = hop->hop_next)
438       dump_trace_hop(trace, hop);
439 
440   /* dump any last-ditch probing hops */
441   for(hop = trace->lastditch; hop != NULL; hop = hop->hop_next)
442     dump_trace_hop(trace, hop);
443 
444   if((pmtud = trace->pmtud) != NULL)
445     {
446       printf("pmtud: ver %d ifmtu %d, pmtu %d", pmtud->ver, pmtud->ifmtu,
447 	     pmtud->pmtu);
448       if(pmtud->outmtu != 0)
449 	printf(", outmtu %d", pmtud->outmtu);
450       if(pmtud->notec != 0)
451 	printf(", notec %d", pmtud->notec);
452       printf("\n");
453       for(u8=0; u8<pmtud->notec; u8++)
454 	{
455 	  n = pmtud->notes[u8];
456 	  hop = n->hop;
457 	  printf(" note %d: nhmtu %d, ", u8, n->nhmtu);
458 
459 	  if(hop != NULL)
460 	    scamper_addr_tostr(hop->hop_addr, buf, sizeof(buf));
461 	  else
462 	    buf[0] = '\0';
463 
464 	  if(n->type == SCAMPER_TRACE_PMTUD_N_TYPE_PTB)
465 	    printf("ptb %s", buf);
466 	  else if(n->type == SCAMPER_TRACE_PMTUD_N_TYPE_PTB_BAD && hop != NULL)
467 	    printf("ptb-bad %s mtu %d", buf, hop->hop_icmp_nhmtu);
468 	  else if(n->type == SCAMPER_TRACE_PMTUD_N_TYPE_SILENCE)
469 	    printf("silence > ttl %d", hop != NULL ? hop->hop_probe_ttl : 0);
470 	  else
471 	    printf("type-%d", n->type);
472 	  printf("\n");
473 	}
474       for(hop = trace->pmtud->hops; hop != NULL; hop = hop->hop_next)
475 	dump_trace_hop(trace, hop);
476     }
477 
478   printf("\n");
479 
480   scamper_trace_free(trace);
481 
482   return;
483 }
484 
dump_tracelb_reply(scamper_tracelb_probe_t * probe,scamper_tracelb_reply_t * reply)485 static void dump_tracelb_reply(scamper_tracelb_probe_t *probe,
486 			       scamper_tracelb_reply_t *reply)
487 {
488   scamper_icmpext_t *ie;
489   struct timeval rtt;
490   char from[32];
491   uint32_t u32;
492   uint16_t m;
493 
494   timeval_diff_tv(&rtt, &probe->tx, &reply->reply_rx);
495 
496   if(reply->reply_from != NULL)
497     scamper_addr_tostr(reply->reply_from, from, sizeof(from));
498   else
499     snprintf(from, sizeof(from), "<null>");
500 
501   printf("   reply from: %s, rtt: %d.%06d, ttl: %d",
502 	 from, (int)rtt.tv_sec, (int)rtt.tv_usec, reply->reply_ttl);
503 
504   if(reply->reply_from != NULL && SCAMPER_ADDR_TYPE_IS_IPV4(reply->reply_from))
505     printf(", ipid: 0x%04x", reply->reply_ipid);
506   printf("\n");
507 
508   if(reply->reply_flags & SCAMPER_TRACELB_REPLY_FLAG_TCP)
509     {
510       printf("     tcp flags 0x%02x", reply->reply_tcp_flags);
511       dump_tcp_flags(reply->reply_tcp_flags);
512       printf("\n");
513     }
514   else
515     {
516       printf("     icmp: %d/%d, q-tos: 0x%02x",
517 	     reply->reply_icmp_type, reply->reply_icmp_code,
518 	     reply->reply_icmp_q_tos);
519       if(SCAMPER_TRACELB_REPLY_IS_ICMP_UNREACH(reply) ||
520 	 SCAMPER_TRACELB_REPLY_IS_ICMP_TTL_EXP(reply))
521 	{
522 	  printf(", q-ttl: %d", reply->reply_icmp_q_ttl);
523 	}
524       printf("\n");
525 
526       for(ie = reply->reply_icmp_ext; ie != NULL; ie = ie->ie_next)
527 	{
528 	  if(SCAMPER_ICMPEXT_IS_MPLS(ie))
529 	    {
530 	      for(m=0; m<SCAMPER_ICMPEXT_MPLS_COUNT(ie); m++)
531 		{
532 		  u32 = SCAMPER_ICMPEXT_MPLS_LABEL(ie, m);
533 		  printf("   %9s: label %d exp %d s %d ttl %d\n",
534 			 (m == 0) ? "  icmp-ext mpls" : "", u32,
535 			 SCAMPER_ICMPEXT_MPLS_EXP(ie, m),
536 			 SCAMPER_ICMPEXT_MPLS_S(ie, m),
537 			 SCAMPER_ICMPEXT_MPLS_TTL(ie, m));
538 		}
539 	    }
540 	}
541     }
542 
543   return;
544 }
545 
dump_tracelb_probe(scamper_tracelb_t * trace,scamper_tracelb_probe_t * probe)546 static void dump_tracelb_probe(scamper_tracelb_t *trace,
547 			       scamper_tracelb_probe_t *probe)
548 {
549   uint32_t i;
550 
551   printf("  probe flowid: %d, ttl: %d, attempt: %d, tx: %d.%06d\n",
552 	 probe->flowid, probe->ttl, probe->attempt,
553 	 (int)probe->tx.tv_sec, (int)probe->tx.tv_usec);
554 
555   for(i=0; i<probe->rxc; i++)
556     {
557       dump_tracelb_reply(probe, probe->rxs[i]);
558     }
559 
560   return;
561 }
562 
dump_tracelb(scamper_tracelb_t * trace)563 static void dump_tracelb(scamper_tracelb_t *trace)
564 {
565   static const char *flags[] = {
566     "ptr"
567   };
568   scamper_tracelb_link_t *link;
569   scamper_tracelb_node_t *node;
570   scamper_tracelb_probeset_t *set;
571   char src[256], dst[256];
572   uint16_t i, j, k, l;
573 
574   if(trace->src != NULL)
575     {
576       printf("tracelb from %s to %s\n",
577 	     scamper_addr_tostr(trace->src, src, sizeof(src)),
578 	     scamper_addr_tostr(trace->dst, dst, sizeof(dst)));
579     }
580   else
581     {
582       printf("tracelb to %s\n",
583 	     scamper_addr_tostr(trace->dst, dst, sizeof(dst)));
584     }
585 
586   dump_list_summary(trace->list);
587   dump_cycle_summary(trace->cycle);
588   printf(" user-id: %d\n", trace->userid);
589   if(trace->rtr != NULL)
590     printf(" rtr: %s\n", scamper_addr_tostr(trace->rtr, src, sizeof(src)));
591   dump_timeval("start", &trace->start);
592 
593   printf(" type: ");
594   switch(trace->type)
595     {
596     case SCAMPER_TRACELB_TYPE_ICMP_ECHO:
597       printf("icmp-echo id: %d", trace->sport);
598       break;
599 
600     case SCAMPER_TRACELB_TYPE_UDP_DPORT:
601       printf("udp-dport %d:%d", trace->sport, trace->dport);
602       break;
603 
604     case SCAMPER_TRACELB_TYPE_UDP_SPORT:
605       printf("udp-sport %d:%d", trace->sport, trace->dport);
606       break;
607 
608     case SCAMPER_TRACELB_TYPE_TCP_SPORT:
609       printf("tcp-sport %d:%d", trace->sport, trace->dport);
610       break;
611 
612     case SCAMPER_TRACELB_TYPE_TCP_ACK_SPORT:
613       printf("tcp-ack-sport %d:%d", trace->sport, trace->dport);
614       break;
615 
616     default:
617       printf("%d", trace->type);
618       break;
619     }
620   printf(", tos: 0x%02x\n", trace->tos);
621 
622   printf(" firsthop: %d, attempts: %d, confidence: %d\n",
623 	 trace->firsthop, trace->attempts, trace->confidence);
624   printf(" probe-size: %d, wait-probe: %dms, wait-timeout %ds\n",
625 	 trace->probe_size, trace->wait_probe * 10, trace->wait_timeout);
626   printf(" nodec: %d, linkc: %d, probec: %d, probec_max: %d\n",
627 	 trace->nodec, trace->linkc, trace->probec, trace->probec_max);
628   if(trace->flags != 0)
629     {
630       printf(" flags:");
631       l = 0;
632       for(i=0; i<1; i++)
633 	{
634 	  if((trace->flags & (0x1 << i)) == 0)
635 	    continue;
636 	  if(l > 0)
637 	    printf(",");
638 	  printf(" %s", flags[i]);
639 	  l++;
640 	}
641       printf("\n");
642     }
643 
644   for(i=0; i<trace->nodec; i++)
645     {
646       node = trace->nodes[i];
647 
648       if(node->addr != NULL)
649 	scamper_addr_tostr(node->addr, src, sizeof(src));
650       else
651 	snprintf(src, sizeof(src), "*");
652 
653       printf("node %d %s", i, src);
654       if(SCAMPER_TRACELB_NODE_QTTL(node) != 0)
655 	printf(", q-ttl %d", node->q_ttl);
656       if(node->name != NULL)
657 	printf(", name %s", node->name);
658       printf("\n");
659 
660       for(j=0; j<node->linkc; j++)
661 	{
662 	  link = node->links[j];
663 	  if(link->from->addr != NULL)
664 	    scamper_addr_tostr(link->from->addr, src, sizeof(src));
665 	  else
666 	    snprintf(src, sizeof(src), "*");
667 	  if(link->to != NULL)
668 	    scamper_addr_tostr(link->to->addr, dst, sizeof(dst));
669 	  else
670 	    snprintf(dst, sizeof(dst), "*");
671 	  printf(" link %s -> %s hopc %d\n", src, dst, link->hopc);
672 
673 	  for(k=0; k<link->hopc; k++)
674 	    {
675 	      set = link->sets[k];
676 	      for(l=0; l<set->probec; l++)
677 		dump_tracelb_probe(trace, set->probes[l]);
678 	    }
679 	}
680     }
681 
682   printf("\n");
683 
684   scamper_tracelb_free(trace);
685   return;
686 }
687 
ping_tsreply_tostr(char * buf,size_t len,uint32_t val)688 static char *ping_tsreply_tostr(char *buf, size_t len, uint32_t val)
689 {
690   uint32_t hh, mm, ss, ms;
691   ms = val % 1000;
692   ss = val / 1000;
693   hh = ss / 3600; ss -= (hh * 3600);
694   mm = ss / 60; ss -= (mm * 60);
695   snprintf(buf, len, "%02d:%02d:%02d.%03d", hh, mm, ss, ms);
696   return buf;
697 }
698 
dump_ping_reply(const scamper_ping_t * ping,const scamper_ping_reply_t * reply)699 static void dump_ping_reply(const scamper_ping_t *ping,
700 			    const scamper_ping_reply_t *reply)
701 {
702   scamper_ping_reply_v4rr_t *v4rr;
703   scamper_ping_reply_v4ts_t *v4ts;
704   scamper_ping_reply_tsreply_t *tsreply;
705   uint8_t i;
706   char buf[256];
707   struct timeval txoff;
708 
709   printf("reply from %s, attempt: %d",
710 	 scamper_addr_tostr(reply->addr, buf, sizeof(buf)), reply->probe_id+1);
711   if(timeval_cmp(&reply->tx, &ping->start) >= 0)
712     {
713       timeval_diff_tv(&txoff, &ping->start, &reply->tx);
714       printf(", tx: %d.%06ds", (int)txoff.tv_sec, (int)txoff.tv_usec);
715     }
716   printf(", rtt: %d.%06ds\n", (int)reply->rtt.tv_sec, (int)reply->rtt.tv_usec);
717 
718   printf(" size: %d", reply->reply_size);
719   if(reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_TTL)
720     printf(", ttl: %d", reply->reply_ttl);
721   if(reply->flags & SCAMPER_PING_REPLY_FLAG_PROBE_IPID)
722     printf(", probe-ipid: 0x%04x", reply->probe_ipid);
723   if(reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_IPID)
724     {
725       if(SCAMPER_ADDR_TYPE_IS_IPV4(reply->addr))
726 	printf(", reply-ipid: 0x%04x", reply->reply_ipid);
727       else
728 	printf(", reply-ipid32: 0x%08x", reply->reply_ipid32);
729     }
730   printf("\n");
731 
732   if(SCAMPER_PING_REPLY_IS_ICMP(reply))
733     {
734       printf(" icmp type: %d, code: %d\n", reply->icmp_type, reply->icmp_code);
735     }
736   else if(SCAMPER_PING_REPLY_IS_TCP(reply))
737     {
738       printf(" tcp flags: %02x", reply->tcp_flags);
739       dump_tcp_flags(reply->tcp_flags);
740       printf("\n");
741     }
742 
743   if((tsreply = reply->tsreply) != NULL)
744     {
745       printf(" icmp-tsreply:");
746       printf(" tso=%s", ping_tsreply_tostr(buf, sizeof(buf), tsreply->tso));
747       printf(" tsr=%s", ping_tsreply_tostr(buf, sizeof(buf), tsreply->tsr));
748       printf(" tst=%s\n", ping_tsreply_tostr(buf, sizeof(buf), tsreply->tst));
749     }
750 
751   if((v4rr = reply->v4rr) != NULL)
752     {
753       printf(" record route:");
754       for(i=0; i<v4rr->rrc; i++)
755 	{
756 	  if((i % 3) == 0 && i != 0)
757 	    printf("\n              ");
758 
759 	  printf(" %-15s",
760 		 scamper_addr_tostr(v4rr->rr[i],buf,sizeof(buf)));
761 	}
762       printf("\n");
763     }
764 
765   if((v4ts = reply->v4ts) != NULL)
766     {
767       printf(" IP timestamp option: tsc %d", v4ts->tsc);
768       if(v4ts->ips != NULL)
769 	{
770 	  for(i=0; i<v4ts->tsc; i++)
771 	    {
772 	      if((i % 2) == 0)
773 		printf("\n  ");
774 	      else if(i != 0)
775 		printf("    ");
776 
777 	      printf("%-15s 0x%08x",
778 		     scamper_addr_tostr(v4ts->ips[i], buf, sizeof(buf)),
779 		     v4ts->tss[i]);
780 	    }
781 	}
782       else
783 	{
784 	  for(i=0; i<v4ts->tsc; i++)
785 	    {
786 	      if((i % 3) == 0)
787 		printf("\n  ");
788 	      printf(" 0x%08x", v4ts->tss[i]);
789 	    }
790 	}
791       printf("\n");
792     }
793 
794   return;
795 }
796 
dump_ping(scamper_ping_t * ping)797 static void dump_ping(scamper_ping_t *ping)
798 {
799   static const char *flags[] = {
800     "v4rr", "spoof", "payload", "tsonly", "tsandaddr", "icmpsum", "dl", "tbt",
801     "nosrc",
802   };
803   scamper_ping_reply_t *reply;
804   char buf[256];
805   uint32_t u32;
806   int i;
807 
808   scamper_addr_tostr(ping->src, buf, sizeof(buf));
809   printf("ping from %s", buf);
810   if(ping->flags & SCAMPER_PING_FLAG_SPOOF)
811     printf(" (spoofed)");
812   scamper_addr_tostr(ping->dst, buf, sizeof(buf));
813   printf(" to %s\n", buf);
814 
815   dump_list_summary(ping->list);
816   dump_cycle_summary(ping->cycle);
817   printf(" user-id: %d\n", ping->userid);
818   if(ping->rtr != NULL)
819     printf(" rtr: %s\n", scamper_addr_tostr(ping->rtr, buf, sizeof(buf)));
820   dump_timeval("start", &ping->start);
821 
822   printf(" probe-count: %d", ping->probe_count);
823   if(ping->reply_count > 0)
824     printf(", replies-req: %d", ping->reply_count);
825   printf(", size: %d", ping->probe_size);
826   if(ping->reply_pmtu > 0)
827     printf(", reply-pmtu: %d", ping->reply_pmtu);
828   printf(", wait: %u", ping->probe_wait);
829   if(ping->probe_wait_us > 0)
830     {
831       u32 = ping->probe_wait_us;
832       while((u32 % 10) == 0)
833 	u32 /= 10;
834       printf(".%u", u32);
835     }
836   printf(", timeout: %u, ttl: %u", ping->probe_timeout, ping->probe_ttl);
837   printf("\n");
838 
839   if(ping->flags != 0)
840     {
841       printf(" flags:");
842       u32 = 0;
843       for(i=0; i<9; i++)
844 	{
845 	  if((ping->flags & (0x1 << i)) == 0)
846 	    continue;
847 	  if(u32 > 0)
848 	    printf(",");
849 	  printf(" %s", flags[i]);
850 	  u32++;
851 	}
852       printf("\n");
853     }
854 
855   printf(" method: %s", scamper_ping_method2str(ping, buf, sizeof(buf)));
856   switch(ping->probe_method)
857     {
858     case SCAMPER_PING_METHOD_ICMP_ECHO:
859     case SCAMPER_PING_METHOD_ICMP_TIME:
860       if((ping->flags & SCAMPER_PING_FLAG_ICMPSUM) != 0)
861 	printf(", icmp-csum: %04x", ping->probe_icmpsum);
862       break;
863 
864     case SCAMPER_PING_METHOD_UDP:
865     case SCAMPER_PING_METHOD_TCP_ACK:
866     case SCAMPER_PING_METHOD_TCP_SYN:
867     case SCAMPER_PING_METHOD_TCP_RST:
868     case SCAMPER_PING_METHOD_TCP_SYNACK:
869       printf(", sport: %d, dport: %d", ping->probe_sport, ping->probe_dport);
870       break;
871 
872     case SCAMPER_PING_METHOD_TCP_ACK_SPORT:
873       printf(", base-sport: %d, dport: %d",
874 	     ping->probe_sport, ping->probe_dport);
875       break;
876 
877     case SCAMPER_PING_METHOD_UDP_DPORT:
878       printf(", sport: %d, base-dport %d",
879 	     ping->probe_sport, ping->probe_dport);
880       break;
881     }
882 
883   if(SCAMPER_PING_METHOD_IS_TCP(ping))
884     printf(", seq: %u, ack: %u", ping->probe_tcpseq, ping->probe_tcpack);
885 
886   printf("\n");
887 
888   if(ping->probe_tsps != NULL)
889     {
890       printf(" timestamp-prespec:");
891       for(i=0; i<ping->probe_tsps->ipc; i++)
892 	printf(" %s",
893 	       scamper_addr_tostr(ping->probe_tsps->ips[i],buf,sizeof(buf)));
894       printf("\n");
895     }
896 
897   /* dump pad bytes, if used */
898   if(ping->probe_datalen > 0 && ping->probe_data != NULL)
899     {
900       if((ping->flags & SCAMPER_PING_FLAG_PAYLOAD) != 0)
901 	printf(" payload");
902       else
903 	printf(" pattern");
904       printf(" bytes (%d): ", ping->probe_datalen);
905       for(i=0; i<ping->probe_datalen; i++)
906 	printf("%02x", ping->probe_data[i]);
907       printf("\n");
908     }
909 
910   printf(" probes-sent: %d, stop-reason: ", ping->ping_sent);
911   switch(ping->stop_reason)
912     {
913     case SCAMPER_PING_STOP_NONE:
914       printf("none"); break;
915 
916     case SCAMPER_PING_STOP_COMPLETED:
917       printf("done"); break;
918 
919     case SCAMPER_PING_STOP_ERROR:
920       printf("sendto errno %d", ping->stop_data); break;
921 
922     case SCAMPER_PING_STOP_HALTED:
923       printf("halted"); break;
924 
925     default:
926       printf("reason 0x%02x data 0x%02x",
927 	      ping->stop_reason, ping->stop_data);
928       break;
929     }
930   printf("\n");
931 
932   for(i=0; i<ping->ping_sent; i++)
933     {
934       for(reply = ping->ping_replies[i]; reply != NULL; reply = reply->next)
935 	{
936 	  dump_ping_reply(ping, reply);
937 	}
938     }
939 
940   printf("\n");
941 
942   scamper_ping_free(ping);
943 
944   return;
945 }
946 
dump_dealias_probedef(scamper_dealias_probedef_t * def)947 static void dump_dealias_probedef(scamper_dealias_probedef_t *def)
948 {
949   scamper_dealias_probedef_icmp_t *icmp;
950   char dst[128], src[128];
951 
952   printf(" probedef %d: dst: %s, ttl: %d, tos: 0x%02x\n  src: %s",
953 	 def->id,
954 	 scamper_addr_tostr(def->dst, dst, sizeof(dst)),
955 	 def->ttl, def->tos,
956 	 scamper_addr_tostr(def->src, src, sizeof(src)));
957   if(def->size > 0)
958     printf(", size: %d", def->size);
959   if(def->mtu > 0)
960     printf(", mtu: %d", def->mtu);
961   printf("\n");
962 
963   if(SCAMPER_DEALIAS_PROBEDEF_PROTO_IS_ICMP(def))
964     {
965       icmp = &def->un.icmp;
966       printf("  icmp-echo csum: %04x, id: %04x\n", icmp->csum, icmp->id);
967     }
968   else if(SCAMPER_DEALIAS_PROBEDEF_PROTO_IS_UDP(def))
969     {
970       if(def->method == SCAMPER_DEALIAS_PROBEDEF_METHOD_UDP)
971 	printf("  udp");
972       else if(def->method == SCAMPER_DEALIAS_PROBEDEF_METHOD_UDP_DPORT)
973 	printf("  udp-dport");
974       else
975 	printf("  udp-%d", def->method);
976       printf(" %d:%d\n", def->un.udp.sport, def->un.udp.dport);
977     }
978   else if(SCAMPER_DEALIAS_PROBEDEF_PROTO_IS_TCP(def))
979     {
980       if(def->method == SCAMPER_DEALIAS_PROBEDEF_METHOD_TCP_ACK)
981 	printf("  tcp-ack");
982       else if(def->method == SCAMPER_DEALIAS_PROBEDEF_METHOD_TCP_ACK_SPORT)
983 	printf("  tcp-ack-sport");
984       else if(def->method == SCAMPER_DEALIAS_PROBEDEF_METHOD_TCP_SYN_SPORT)
985 	printf("  tcp-syn-sport");
986       else
987 	printf("  tcp-%d", def->method);
988       printf(" %d:%d ", def->un.tcp.sport, def->un.tcp.dport);
989       dump_tcp_flags(def->un.tcp.flags);
990       printf("\n");
991     }
992   else
993     {
994       printf("%d\n", def->method);
995     }
996   return;
997 }
998 
dump_dealias(scamper_dealias_t * dealias)999 static void dump_dealias(scamper_dealias_t *dealias)
1000 {
1001   scamper_dealias_prefixscan_t *ps = dealias->data;
1002   scamper_dealias_mercator_t *mercator = dealias->data;
1003   scamper_dealias_radargun_t *radargun = dealias->data;
1004   scamper_dealias_ally_t *ally = dealias->data;
1005   scamper_dealias_bump_t *bump = dealias->data;
1006   scamper_dealias_probe_t *probe;
1007   scamper_dealias_reply_t *reply;
1008   struct timeval rtt;
1009   uint32_t i;
1010   uint16_t u16;
1011   uint8_t u8;
1012   char buf[256];
1013   int j;
1014 
1015   /* first line: dealias */
1016   printf("dealias");
1017   if(dealias->method == SCAMPER_DEALIAS_METHOD_MERCATOR)
1018     {
1019       scamper_addr_tostr(mercator->probedef.src, buf, sizeof(buf));
1020       printf(" from %s", buf);
1021       scamper_addr_tostr(mercator->probedef.dst, buf, sizeof(buf));
1022       printf(" to %s", buf);
1023     }
1024   printf("\n");
1025 
1026   /* dump list, cycle, start time */
1027   dump_list_summary(dealias->list);
1028   dump_cycle_summary(dealias->cycle);
1029   printf(" user-id: %d\n", dealias->userid);
1030   dump_timeval("start", &dealias->start);
1031 
1032   /* method headers */
1033   printf(" method: ");
1034   if(dealias->method == SCAMPER_DEALIAS_METHOD_MERCATOR)
1035     {
1036       printf("mercator, attempts: %d, timeout: %ds\n",
1037 	     mercator->attempts, mercator->wait_timeout);
1038       dump_dealias_probedef(&mercator->probedef);
1039     }
1040   else if(dealias->method == SCAMPER_DEALIAS_METHOD_ALLY)
1041     {
1042       printf("ally, attempts: %d, fudge: %d, "
1043 	     "wait-probe: %dms, wait-timeout: %ds",
1044 	     ally->attempts,ally->fudge,ally->wait_probe,ally->wait_timeout);
1045       if(SCAMPER_DEALIAS_ALLY_IS_NOBS(dealias))
1046 	printf(", nobs");
1047       printf("\n");
1048 
1049       dump_dealias_probedef(&ally->probedefs[0]);
1050       dump_dealias_probedef(&ally->probedefs[1]);
1051     }
1052   else if(dealias->method == SCAMPER_DEALIAS_METHOD_BUMP)
1053     {
1054       printf("bump, attempts: %d, wait-probe: %dms, bump-limit: %d\n",
1055 	     bump->attempts, bump->wait_probe, bump->bump_limit);
1056       dump_dealias_probedef(&bump->probedefs[0]);
1057       dump_dealias_probedef(&bump->probedefs[1]);
1058     }
1059   else if(dealias->method == SCAMPER_DEALIAS_METHOD_RADARGUN)
1060     {
1061       printf("radargun, wait-probe: %dms, wait-round: %dms\n"
1062 	     "  wait-timeout: %ds, attempts: %d, probedefc: %d\n",
1063 	     radargun->wait_probe, radargun->wait_round,
1064 	     radargun->wait_timeout, radargun->attempts, radargun->probedefc);
1065       if((u8 = radargun->flags) != 0)
1066 	{
1067 	  printf("  flags: ");
1068 	  for(i=0; i<8; i++)
1069 	    {
1070 	      if((u8 & (1 << i)) == 0)
1071 		continue;
1072 	      switch(1 << i)
1073 		{
1074 		case SCAMPER_DEALIAS_RADARGUN_FLAG_SHUFFLE:
1075 		  printf("shuffle");
1076 		  break;
1077 
1078 		default:
1079 		  printf("0x%02x", 1<<i);
1080 		  break;
1081 		}
1082 
1083 	      u8 &= ~(1 << i);
1084 	      if(u8 != 0)
1085 		printf(", ");
1086 	      else
1087 		break;
1088 	    }
1089 	  printf("\n");
1090 	}
1091       for(i=0; i<radargun->probedefc; i++)
1092 	dump_dealias_probedef(&radargun->probedefs[i]);
1093     }
1094   else if(dealias->method == SCAMPER_DEALIAS_METHOD_PREFIXSCAN)
1095     {
1096       printf("prefixscan, %s:",
1097 	     scamper_addr_tostr(ps->a, buf, sizeof(buf)));
1098       printf("%s/%d",
1099 	     scamper_addr_tostr(ps->b, buf, sizeof(buf)), ps->prefix);
1100       if(ps->ab != NULL)
1101 	printf(", alias: %s/%d",
1102 	       scamper_addr_tostr(ps->ab, buf, sizeof(buf)),
1103 	       scamper_addr_prefixhosts(ps->b, ps->ab));
1104       printf("\n");
1105 
1106       printf("  attempts: %d, replyc: %d, fudge: %d, wait-probe: %dms, "
1107 	     "wait-timeout: %ds", ps->attempts, ps->replyc, ps->fudge,
1108 	     ps->wait_probe, ps->wait_timeout);
1109       if(SCAMPER_DEALIAS_PREFIXSCAN_IS_NOBS(dealias))
1110 	printf(", nobs");
1111       printf("\n");
1112       if(ps->xc > 0)
1113 	{
1114 	  printf("  exclude:");
1115 	  for(u16=0; u16<ps->xc; u16++)
1116 	    printf(" %s", scamper_addr_tostr(ps->xs[u16], buf, sizeof(buf)));
1117 	  printf("\n");
1118 	}
1119       for(i=0; i<ps->probedefc; i++)
1120 	dump_dealias_probedef(&ps->probedefs[i]);
1121     }
1122   else
1123     {
1124       printf("%d\n", dealias->method);
1125     }
1126 
1127   printf(" probes: %d, result: %s", dealias->probec,
1128 	 scamper_dealias_result_tostr(dealias, buf, sizeof(buf)));
1129 
1130   if(dealias->method == SCAMPER_DEALIAS_METHOD_PREFIXSCAN &&
1131      ps->flags & SCAMPER_DEALIAS_PREFIXSCAN_FLAG_CSA)
1132     printf(", csa");
1133   printf("\n");
1134 
1135   for(i=0; i<dealias->probec; i++)
1136     {
1137       probe = dealias->probes[i];
1138       printf(" probe: %d, def: %d, seq: %d, tx: %d.%06d",
1139 	     i, probe->def->id, probe->seq,
1140 	     (int)probe->tx.tv_sec, (int)probe->tx.tv_usec);
1141       if(SCAMPER_ADDR_TYPE_IS_IPV4(probe->def->dst))
1142 	printf(", ipid: %04x", probe->ipid);
1143       printf("\n");
1144 
1145       for(j=0; j<probe->replyc; j++)
1146 	{
1147 	  reply = probe->replies[j];
1148 	  timeval_diff_tv(&rtt, &probe->tx, &reply->rx);
1149 	  printf("  reply: %d, src: %s, ttl: %d, rtt: %d.%06d",
1150 		 j, scamper_addr_tostr(reply->src, buf, sizeof(buf)),
1151 		 reply->ttl, (int)rtt.tv_sec, (int)rtt.tv_usec);
1152 	  if(SCAMPER_ADDR_TYPE_IS_IPV4(reply->src))
1153 	    printf(", ipid: %04x", reply->ipid);
1154 	  else if(reply->flags & SCAMPER_DEALIAS_REPLY_FLAG_IPID32)
1155 	    printf(", ipid32: %08x", reply->ipid32);
1156 	  printf("\n");
1157 
1158 	  if(SCAMPER_DEALIAS_REPLY_IS_ICMP(reply))
1159 	    {
1160 	      printf("  icmp-type: %d, icmp-code: %d",
1161 		     reply->icmp_type, reply->icmp_code);
1162 
1163 	      if(SCAMPER_DEALIAS_REPLY_IS_ICMP_UNREACH(reply) ||
1164 		 SCAMPER_DEALIAS_REPLY_IS_ICMP_TTL_EXP(reply))
1165 		{
1166 		  printf(", icmp-q-ttl: %d", reply->icmp_q_ip_ttl);
1167 		}
1168 	      printf("\n");
1169 	    }
1170 	  else if(SCAMPER_DEALIAS_REPLY_IS_TCP(reply))
1171 	    {
1172 	      printf("   tcp flags:");
1173 	      dump_tcp_flags(reply->tcp_flags);
1174 	      printf("\n");
1175 	    }
1176 	  else
1177 	    {
1178 	      printf("  reply proto %d\n", reply->proto);
1179 	    }
1180 	}
1181     }
1182 
1183   printf("\n");
1184 
1185   scamper_dealias_free(dealias);
1186   return;
1187 }
1188 
dump_neighbourdisc(scamper_neighbourdisc_t * nd)1189 static void dump_neighbourdisc(scamper_neighbourdisc_t *nd)
1190 {
1191   scamper_neighbourdisc_probe_t *probe;
1192   scamper_neighbourdisc_reply_t *reply;
1193   struct timeval rtt;
1194   uint16_t i, j;
1195   char buf[128];
1196 
1197   printf("neighbourdisc\n");
1198   dump_list_summary(nd->list);
1199   dump_cycle_summary(nd->cycle);
1200   printf(" user-id: %d\n", nd->userid);
1201   dump_timeval("start", &nd->start);
1202 
1203   if(nd->method == SCAMPER_NEIGHBOURDISC_METHOD_ARP ||
1204      nd->method == SCAMPER_NEIGHBOURDISC_METHOD_ND_NSOL)
1205     {
1206       if(nd->method == SCAMPER_NEIGHBOURDISC_METHOD_ARP)
1207 	printf(" method: arp");
1208       else
1209 	printf(" method: ipv6 nsol");
1210 
1211       printf(", attempts: %d, wait: %ds, replyc: %d, iface: %s\n",
1212 	     nd->attempts, nd->wait, nd->replyc, nd->ifname);
1213       printf(" our-mac: %s\n",
1214 	     scamper_addr_tostr(nd->src_mac, buf, sizeof(buf)));
1215       printf(" flags: 0x%02x", nd->flags);
1216       if(nd->flags != 0)
1217 	{
1218 	  printf(" (");
1219 	  if(nd->flags & SCAMPER_NEIGHBOURDISC_FLAG_ALLATTEMPTS)
1220 	    printf(" all-attempts");
1221 	  if(nd->flags & SCAMPER_NEIGHBOURDISC_FLAG_FIRSTRESPONSE)
1222 	    printf(" first-response");
1223 	  printf(" )");
1224 	}
1225       printf("\n");
1226       printf(" query:  who-has %s",
1227 	     scamper_addr_tostr(nd->dst_ip, buf, sizeof(buf)));
1228       if(nd->src_ip != NULL)
1229 	printf(" tell %s", scamper_addr_tostr(nd->src_ip, buf, sizeof(buf)));
1230       if(nd->dst_mac != NULL)
1231 	printf(" result: %s is-at %s\n", buf,
1232 	       scamper_addr_tostr(nd->dst_mac, buf, sizeof(buf)));
1233     }
1234 
1235   for(i=0; i<nd->probec; i++)
1236     {
1237       probe = nd->probes[i];
1238       printf(" probe: %d, tx: %d.%06d\n",
1239 	     i, (int)probe->tx.tv_sec, (int)probe->tx.tv_usec);
1240 
1241       for(j=0; j<probe->rxc; j++)
1242 	{
1243 	  reply = probe->rxs[j];
1244 	  timeval_diff_tv(&rtt, &probe->tx, &reply->rx);
1245 	  printf("  reply: %d, rtt: %d.%06d, mac: %s\n",
1246 		 i, (int)rtt.tv_sec, (int)rtt.tv_usec,
1247 		 scamper_addr_tostr(reply->mac, buf, sizeof(buf)));
1248 	}
1249     }
1250 
1251   printf("\n");
1252 
1253   scamper_neighbourdisc_free(nd);
1254   return;
1255 }
1256 
tbit_bits_print(uint32_t flags,int bits,const char ** f2s,int f2sc)1257 static void tbit_bits_print(uint32_t flags,int bits, const char **f2s,int f2sc)
1258 {
1259   int i, f = 0;
1260   uint32_t u32;
1261 
1262   if(flags == 0)
1263     return;
1264   for(i=0; i<bits; i++)
1265     {
1266       if((u32 = flags & (0x1 << i)) == 0) continue;
1267       if(f > 0) printf(",");
1268       if(i < f2sc)
1269 	printf(" %s", f2s[i]);
1270       else
1271 	printf(" 0x%x", u32);
1272       f++;
1273     }
1274   return;
1275 }
1276 
tbit_isnoff(uint32_t isn,uint32_t seq)1277 static uint32_t tbit_isnoff(uint32_t isn, uint32_t seq)
1278 {
1279   if(seq >= isn)
1280     return seq - isn;
1281   return TCP_MAX_SEQNUM - isn + seq + 1;
1282 }
1283 
dump_tbit(scamper_tbit_t * tbit)1284 static void dump_tbit(scamper_tbit_t *tbit)
1285 {
1286   static const char *tbit_options[] = {"tcpts", "sack"};
1287   static const char *null_options[] = {"tcpts", "ipts-syn", "iprr-syn",
1288 				       "ipqs-syn", "sack", "fo", "fo-exp"};
1289   static const char *null_results[] = {"tcpts-ok", "sack-ok", "fo-ok"};
1290   scamper_tbit_pmtud_t *pmtud;
1291   scamper_tbit_null_t *null;
1292   scamper_tbit_icw_t *icw;
1293   scamper_tbit_blind_t *blind;
1294   scamper_tbit_app_http_t *http;
1295   scamper_tbit_app_bgp_t *bgp;
1296   scamper_tbit_pkt_t *pkt;
1297   struct timeval diff;
1298   uint32_t i;
1299   uint16_t len, u16, datalen;
1300   uint8_t proto, flags, iphlen, tcphlen, mf, ecn, u8, *tmp, txsyn, rxsyn;
1301   uint32_t seq, ack, server_isn, client_isn, off, u32;
1302   char src[64], dst[64], buf[128], ipid[12], fstr[32], tfstr[32], sack[64];
1303   uint8_t cookie[16];
1304   char *str;
1305   size_t soff;
1306   int frag;
1307 
1308   /* Start dumping the tbit test information */
1309   printf("tbit from %s to %s\n",
1310 	 scamper_addr_tostr(tbit->src, src, sizeof(src)),
1311 	 scamper_addr_tostr(tbit->dst, dst, sizeof(dst)));
1312 
1313   dump_list_summary(tbit->list);
1314   dump_cycle_summary(tbit->cycle);
1315   printf(" user-id: %d\n", tbit->userid);
1316   dump_timeval("start", &tbit->start);
1317 
1318   printf(" sport: %d, dport: %d\n", tbit->sport, tbit->dport);
1319   printf(" client-mss: %d, server-mss: %d, ttl: %u",
1320 	 tbit->client_mss, tbit->server_mss, tbit->ttl);
1321   if(tbit->wscale > 0)
1322     printf(", wscale: %u", tbit->wscale);
1323   printf("\n");
1324   printf(" type: %s,", scamper_tbit_type2str(tbit, buf, sizeof(buf)));
1325   printf(" result: %s\n", scamper_tbit_res2str(tbit, buf, sizeof(buf)));
1326   if(tbit->options != 0)
1327     {
1328       printf(" options:");
1329       tbit_bits_print(tbit->options, 32, tbit_options,
1330 		      sizeof(tbit_options) / sizeof(char *));
1331       printf("\n");
1332     }
1333 
1334   if(tbit->fo_cookielen > 0)
1335     {
1336       printf(" fo-cookie: ");
1337       for(u8=0; u8<tbit->fo_cookielen; u8++)
1338 	printf("%02x", tbit->fo_cookie[u8]);
1339       printf("\n");
1340     }
1341 
1342   if(tbit->type == SCAMPER_TBIT_TYPE_PMTUD && tbit->data != NULL)
1343     {
1344       pmtud = tbit->data;
1345       printf(" mtu: %d, ptb-retx: %d", pmtud->mtu, pmtud->ptb_retx);
1346       if(pmtud->ptbsrc != NULL)
1347 	printf(", ptb-src: %s",
1348 	       scamper_addr_tostr(pmtud->ptbsrc, src, sizeof(src)));
1349       if(pmtud->options & SCAMPER_TBIT_PMTUD_OPTION_BLACKHOLE)
1350 	printf(", blackhole");
1351       printf("\n");
1352     }
1353   else if(tbit->type == SCAMPER_TBIT_TYPE_NULL && tbit->data != NULL)
1354     {
1355       null = tbit->data;
1356       if(null->options != 0)
1357 	{
1358 	  printf(" null-options:");
1359 	  tbit_bits_print(null->options, 16, null_options,
1360 			  sizeof(null_options) / sizeof(char *));
1361 	  printf("\n");
1362 	}
1363       if(null->results != 0)
1364 	{
1365 	  printf(" results:");
1366 	  tbit_bits_print(null->results, 16, null_results,
1367 			  sizeof(null_results) / sizeof(char *));
1368 	  printf("\n");
1369 
1370 	  if((null->results & SCAMPER_TBIT_NULL_RESULT_FO) &&
1371 	     scamper_tbit_fo_getcookie(tbit, cookie, &u8) != 0)
1372 	    {
1373 	      printf(" fo-cookie: ");
1374 	      for(i=0; i<u8; i++)
1375 		printf("%02x", cookie[i]);
1376 	      printf("\n");
1377 	    }
1378 	}
1379     }
1380   else if(tbit->type == SCAMPER_TBIT_TYPE_ICW &&
1381 	  tbit->result == SCAMPER_TBIT_RESULT_ICW_SUCCESS)
1382     {
1383       icw = tbit->data;
1384       printf(" icw-start-seq: %u", icw->start_seq);
1385       if(scamper_tbit_icw_size(tbit, &u32) == 0)
1386 	printf(", icw-size: %u bytes", u32);
1387       printf("\n");
1388     }
1389   else if(tbit->type == SCAMPER_TBIT_TYPE_BLIND_RST ||
1390 	  tbit->type == SCAMPER_TBIT_TYPE_BLIND_SYN ||
1391 	  tbit->type == SCAMPER_TBIT_TYPE_BLIND_DATA)
1392     {
1393       blind = tbit->data;
1394       printf(" blind: offset %d, retx %u\n", blind->off, blind->retx);
1395     }
1396 
1397   if(tbit->app_proto == SCAMPER_TBIT_APP_HTTP && tbit->app_data != NULL)
1398     {
1399       http = tbit->app_data;
1400       printf(" app: http");
1401       if(http->type == SCAMPER_TBIT_APP_HTTP_TYPE_HTTPS)
1402 	str = "https";
1403       else
1404 	str = "http";
1405 
1406       if(http->host != NULL && http->file != NULL)
1407 	printf(", url: %s://%s%s", str, http->host, http->file);
1408       else if(http->host != NULL)
1409 	printf(", url: %s://%s", str, http->host);
1410       else
1411 	printf(", file: %s", http->file);
1412       printf("\n");
1413     }
1414   else if(tbit->app_proto == SCAMPER_TBIT_APP_BGP && tbit->app_data != NULL)
1415     {
1416       bgp = tbit->app_data;
1417       printf(" app: bgp, asn: %u\n", bgp->asn);
1418     }
1419 
1420   client_isn = 0;
1421   server_isn = 0;
1422   txsyn      = 0;
1423   rxsyn      = 0;
1424 
1425   for(i=0; i<tbit->pktc; i++)
1426     {
1427       pkt = tbit->pkts[i];
1428       frag = 0; mf = 0; off = 0;
1429       ipid[0] = '\0';
1430 
1431       if((pkt->data[0] >> 4) == 4)
1432         {
1433 	  iphlen = (pkt->data[0] & 0xf) * 4;
1434 	  len = bytes_ntohs(pkt->data+2);
1435 	  proto = pkt->data[9];
1436 	  ecn = pkt->data[1] & 0x3;
1437 	  if(pkt->data[6] & 0x20)
1438 	    mf = 1;
1439 	  off = (bytes_ntohs(pkt->data+6) & 0x1fff) * 8;
1440 	  if(mf != 0 || off != 0)
1441 	    frag = 1;
1442 	  snprintf(ipid, sizeof(ipid), "%04x", bytes_ntohs(pkt->data+4));
1443         }
1444       else if((pkt->data[0] >> 4) == 6)
1445         {
1446 	  iphlen = 40;
1447 	  len = bytes_ntohs(pkt->data+4) + iphlen;
1448 	  proto = pkt->data[6];
1449 	  ecn = (pkt->data[1] & 0x30) >> 4;
1450 
1451 	  for(;;)
1452             {
1453 	      switch(proto)
1454                 {
1455 		case IPPROTO_HOPOPTS:
1456 		case IPPROTO_DSTOPTS:
1457 		case IPPROTO_ROUTING:
1458 		  if(pkt->data[iphlen+1] == 0 ||
1459 		     255 - iphlen <= (pkt->data[iphlen+1] * 8) + 8)
1460 		    break;
1461 		  proto = pkt->data[iphlen+0];
1462 		  iphlen += (pkt->data[iphlen+1] * 8) + 8;
1463 		  continue;
1464 
1465 		case IPPROTO_FRAGMENT:
1466 		  if(255 - iphlen <= 8)
1467 		    break;
1468 		  if(pkt->data[iphlen+3] & 0x1)
1469 		    mf = 1;
1470 		  off = (bytes_ntohs(pkt->data+iphlen+2) & 0xfff8);
1471 		  snprintf(ipid, sizeof(ipid), "%x",
1472 			   bytes_ntohl(pkt->data+iphlen+4));
1473 		  proto = pkt->data[iphlen+0];
1474 		  iphlen += 8;
1475 		  frag = 1;
1476 		  continue;
1477                 }
1478 	      break;
1479             }
1480         }
1481       else
1482 	{
1483 	  continue;
1484 	}
1485 
1486       timeval_diff_tv(&diff, &tbit->start, &pkt->tv);
1487       printf(" [%3d.%03d] %s ", (int)diff.tv_sec, (int)(diff.tv_usec / 1000),
1488 	     pkt->dir == SCAMPER_TBIT_PKT_DIR_TX ? "TX" : "RX");
1489 
1490       if(frag != 0)
1491 	snprintf(fstr,sizeof(fstr),":%u%s", off, mf != 0 ? " MF" : "");
1492       else
1493 	fstr[0] = '\0';
1494 
1495       if(off != 0)
1496 	{
1497 	  printf("%13s %4dF%17s%s%s", "", len, "", ipid, fstr);
1498 	}
1499       else if(proto == IPPROTO_TCP)
1500         {
1501 	  seq     = bytes_ntohl(pkt->data+iphlen+4);
1502 	  ack     = bytes_ntohl(pkt->data+iphlen+8);
1503 	  flags   = pkt->data[iphlen+13];
1504 	  tcphlen = ((pkt->data[iphlen+12] & 0xf0) >> 4) * 4;
1505 
1506 	  soff = 0; tfstr[0] = '\0';
1507 	  if(flags & 0x2)
1508             {
1509 	      if(flags & 0x10)
1510                 {
1511 		  if(rxsyn == 0)
1512 		    {
1513 		      server_isn = seq;
1514 		      rxsyn = 1;
1515 		    }
1516 		  string_concat(tfstr, sizeof(tfstr), &soff, "SYN/ACK");
1517                 }
1518 	      else
1519                 {
1520 		  if(txsyn == 0)
1521 		    {
1522 		      client_isn = seq;
1523 		      txsyn = 1;
1524 		    }
1525 		  string_concat(tfstr, sizeof(tfstr), &soff, "SYN");
1526                 }
1527             }
1528 	  else if(flags & 0x1)
1529 	    string_concat(tfstr, sizeof(tfstr), &soff, "FIN");
1530 	  else if(flags & 0x4)
1531 	    string_concat(tfstr, sizeof(tfstr), &soff, "RST");
1532 
1533 	  if(flags & 0x40)
1534 	    string_concat(tfstr, sizeof(tfstr), &soff, "%sECE",
1535 			  soff != 0 ? "/" : "");
1536 	  if(flags & 0x80)
1537 	    string_concat(tfstr, sizeof(tfstr), &soff, "%sCWR",
1538 			  soff != 0 ? "/" : "");
1539 
1540 	  /* parse TCP options for sack blocks */
1541 	  u8 = 20; soff = 0; sack[0] = '\0';
1542 	  while(u8 < tcphlen)
1543 	    {
1544 	      tmp = pkt->data + iphlen + u8;
1545 
1546 	      if(tmp[0] == 0) /* end of option list */
1547 		break;
1548 
1549 	      if(tmp[0] == 1) /* nop */
1550 		{
1551 		  u8++;
1552 		  continue;
1553 		}
1554 
1555 	      if(tmp[1] == 0 || u8 + tmp[1] > tcphlen)
1556 		break;
1557 
1558 	      /* sack edges */
1559 	      if(tmp[0] == 5 &&
1560 		 (tmp[1]==10 || tmp[1]==18 || tmp[1]==26 || tmp[1]==34))
1561 		{
1562 		  if(pkt->dir == SCAMPER_TBIT_PKT_DIR_TX)
1563 		    u32 = server_isn;
1564 		  else
1565 		    u32 = client_isn;
1566 
1567 		  string_concat(sack, sizeof(sack), &soff, " {");
1568 		  for(u16=0; u16<(tmp[1]-2)/8; u16++)
1569 		    string_concat(sack, sizeof(sack), &soff, "%s%u:%u",
1570 				  u16 != 0 ? "," : "",
1571 				  bytes_ntohl(tmp+2+(u16*8)) - u32,
1572 				  bytes_ntohl(tmp+2+(u16*8)+4) - u32);
1573 		  string_concat(sack, sizeof(sack), &soff, "}");
1574 		}
1575 
1576 	      u8 += tmp[1];
1577 	    }
1578 
1579 	  if(pkt->dir == SCAMPER_TBIT_PKT_DIR_TX)
1580             {
1581 	      seq = tbit_isnoff(client_isn, seq);
1582 	      ack = tbit_isnoff(server_isn, ack);
1583             }
1584 	  else
1585             {
1586 	      if(!(seq == 0 && (flags & TH_RST) != 0))
1587 		seq = tbit_isnoff(server_isn, seq);
1588 	      ack = tbit_isnoff(client_isn, ack);
1589             }
1590 
1591 	  datalen = len - iphlen - tcphlen;
1592 
1593 	  printf("%-13s %4d%s", tfstr, len, frag != 0 ? "F" : " ");
1594 	  soff = 0;
1595 	  string_concat(buf, sizeof(buf), &soff, " %u", seq);
1596 	  if(flags & TH_ACK)
1597 	    string_concat(buf, sizeof(buf), &soff, ":%u", ack);
1598 	  if(datalen != 0)
1599 	    string_concat(buf, sizeof(buf), &soff, "(%d)", datalen);
1600 	  printf("%-17s%s", buf, ipid);
1601 	  if(frag != 0) printf("%s", fstr);
1602 	  if(datalen > 0 && (pkt->data[0] >> 4) == 4 && pkt->data[6] & 0x40)
1603 	    printf(" DF");
1604 	  if(ecn == 3)      printf(" CE");
1605 	  else if(ecn != 0) printf(" ECT");
1606 	  printf("%s", sack);
1607         }
1608       else if(proto == IPPROTO_ICMP)
1609         {
1610 	  if(pkt->data[iphlen+0] == 3 && pkt->data[iphlen+1] == 4)
1611 	    {
1612 	      u16 = bytes_ntohs(pkt->data+iphlen+6);
1613 	      printf("%-13s %4d  mtu = %d", "PTB", len, u16);
1614 	    }
1615         }
1616       else if(proto == IPPROTO_ICMPV6)
1617         {
1618 	  if(pkt->data[iphlen+0] == 2)
1619 	    {
1620 	      u32 = bytes_ntohl(pkt->data+iphlen+4);
1621 	      printf("%-13s %4d  mtu = %d", "PTB", len, u32);
1622 	    }
1623 	}
1624 
1625       printf("\n");
1626     }
1627 
1628   fprintf(stdout,"\n");
1629 
1630   scamper_tbit_free(tbit);
1631   return;
1632 }
1633 
dump_sting(scamper_sting_t * sting)1634 static void dump_sting(scamper_sting_t *sting)
1635 {
1636   scamper_sting_pkt_t *pkt;
1637   struct timeval diff;
1638   char src[64], dst[64], buf[32], ipid[12], tfstr[32], *dir;
1639   uint32_t i, seq, ack, server_isn, client_isn;
1640   uint16_t len, datalen;
1641   uint8_t proto, flags, iphlen, tcphlen;
1642   size_t tfoff;
1643 
1644   printf("sting from %s to %s\n",
1645 	 scamper_addr_tostr(sting->src, src, sizeof(src)),
1646 	 scamper_addr_tostr(sting->dst, dst, sizeof(dst)));
1647 
1648   dump_list_summary(sting->list);
1649   dump_cycle_summary(sting->cycle);
1650   printf(" user-id: %d\n", sting->userid);
1651   dump_timeval("start", &sting->start);
1652   printf(" sport: %d, dport: %d\n", sting->sport, sting->dport);
1653   printf(" count: %d, mean: %dus, inter: %dus, seqskip %d\n",
1654 	 sting->count, sting->mean, sting->inter, sting->seqskip);
1655   printf(" synretx: %d, dataretx: %d\n", sting->synretx, sting->dataretx);
1656   printf(" dataackc: %d, holec: %d\n", sting->dataackc, sting->holec);
1657   printf(" hs-rtt: %d.%06d\n",
1658 	 (int)sting->hsrtt.tv_sec, (int)sting->hsrtt.tv_usec);
1659 
1660   printf(" result: ");
1661   if(sting->result == SCAMPER_STING_RESULT_NONE)
1662     printf("none");
1663   else if(sting->result == SCAMPER_STING_RESULT_COMPLETED)
1664     printf("completed");
1665   else
1666     printf("0x%02x", sting->result);
1667   printf("\n");
1668 
1669   client_isn = 0;
1670   server_isn = 0;
1671 
1672   for(i=0; i<sting->pktc; i++)
1673     {
1674       pkt = sting->pkts[i];
1675 
1676       if((pkt->data[0] >> 4) == 4)
1677         {
1678 	  iphlen = (pkt->data[0] & 0xf) * 4;
1679 	  len = bytes_ntohs(pkt->data+2);
1680 	  proto = pkt->data[9];
1681 	  snprintf(ipid, sizeof(ipid), " %04x", bytes_ntohs(pkt->data+4));
1682 	}
1683       else if((pkt->data[0] >> 4) == 6)
1684         {
1685 	  iphlen = 40;
1686 	  len = bytes_ntohs(pkt->data+4) + iphlen;
1687 	  proto = pkt->data[6];
1688 	  ipid[0] = '\0';
1689 
1690 	  for(;;)
1691             {
1692 	      switch(proto)
1693                 {
1694 		case IPPROTO_HOPOPTS:
1695 		case IPPROTO_DSTOPTS:
1696 		case IPPROTO_ROUTING:
1697 		  if(pkt->data[iphlen+1] == 0 ||
1698 		     255 - iphlen <= (pkt->data[iphlen+1] * 8) + 8)
1699 		    break;
1700 		  proto = pkt->data[iphlen+0];
1701 		  iphlen += (pkt->data[iphlen+1] * 8) + 8;
1702 		  continue;
1703 
1704 		case IPPROTO_FRAGMENT:
1705 		  if(255 - iphlen <= 8)
1706 		    break;
1707 		  proto = pkt->data[iphlen+0];
1708 		  iphlen += 8;
1709 		  continue;
1710                 }
1711 	      break;
1712             }
1713         }
1714       else continue;
1715 
1716       if(proto != IPPROTO_TCP)
1717 	continue;
1718 
1719       timeval_diff_tv(&diff, &sting->start, &pkt->tv);
1720       if(pkt->flags & SCAMPER_STING_PKT_FLAG_TX) dir = "TX";
1721       else if(pkt->flags & SCAMPER_STING_PKT_FLAG_RX) dir = "RX";
1722       else dir = "??";
1723 
1724       printf(" [%3d.%03d] %s ",(int)diff.tv_sec,(int)(diff.tv_usec/1000),dir);
1725 
1726       seq     = bytes_ntohl(pkt->data+iphlen+4);
1727       ack     = bytes_ntohl(pkt->data+iphlen+8);
1728       flags   = pkt->data[iphlen+13];
1729       tcphlen = ((pkt->data[iphlen+12] & 0xf0) >> 4) * 4;
1730 
1731       tfoff = 0;
1732       if(flags & 0x2)
1733 	{
1734 	  if(flags & 0x10)
1735 	    {
1736 	      server_isn = seq;
1737 	      string_concat(tfstr, sizeof(tfstr), &tfoff, "SYN/ACK");
1738 	    }
1739 	  else
1740 	    {
1741 	      client_isn = seq;
1742 	      string_concat(tfstr, sizeof(tfstr), &tfoff, "SYN");
1743 	    }
1744 	}
1745       else if(flags & 0x1)
1746 	string_concat(tfstr, sizeof(tfstr), &tfoff, "FIN");
1747       else if(flags & 0x4)
1748 	string_concat(tfstr, sizeof(tfstr), &tfoff, "RST");
1749 
1750       if(flags & 0x40)
1751 	string_concat(tfstr, sizeof(tfstr), &tfoff, "%sECE",
1752 		      tfoff != 0 ? "/" : "");
1753       if(flags & 0x80)
1754 	string_concat(tfstr, sizeof(tfstr), &tfoff, "%sCWR",
1755 		      tfoff != 0 ? "/" : "");
1756       if(tfoff == 0)
1757 	tfstr[0] = '\0';
1758 
1759       if(pkt->flags & SCAMPER_STING_PKT_FLAG_TX)
1760 	{
1761 	  seq = tbit_isnoff(client_isn, seq);
1762 	  ack = tbit_isnoff(server_isn, ack);
1763 	}
1764       else
1765 	{
1766 	  seq = tbit_isnoff(server_isn, seq);
1767 	  ack = tbit_isnoff(client_isn, ack);
1768 	}
1769 
1770       datalen = len - iphlen - tcphlen;
1771 
1772       printf("%-13s %4d", tfstr, len);
1773       if(datalen != 0)
1774 	snprintf(buf, sizeof(buf), " seq = %u:%u(%d)", seq, ack, datalen);
1775       else
1776 	snprintf(buf, sizeof(buf), " seq = %u:%u", seq, ack);
1777       printf("%-23s%s\n", buf, ipid);
1778     }
1779 
1780   scamper_sting_free(sting);
1781   return;
1782 }
1783 
dump_sniff(scamper_sniff_t * sniff)1784 static void dump_sniff(scamper_sniff_t *sniff)
1785 {
1786   scamper_sniff_pkt_t *pkt;
1787   struct timeval tv;
1788   uint8_t u8, *ptr;
1789   uint32_t i, j;
1790   int k;
1791   char src[64], dst[64], buf[32], *str;
1792 
1793   printf("sniff %s\n", scamper_addr_tostr(sniff->src, src, sizeof(src)));
1794   dump_list_summary(sniff->list);
1795   dump_cycle_summary(sniff->cycle);
1796   printf(" user-id: %d\n", sniff->userid);
1797   dump_timeval("start", &sniff->start);
1798   dump_timeval("finish", &sniff->finish);
1799   printf(" limit-pktc: %d, limit-time: %d, icmp-id %d\n",
1800 	 sniff->limit_pktc, sniff->limit_time, sniff->icmpid);
1801   switch(sniff->stop_reason)
1802     {
1803     case SCAMPER_SNIFF_STOP_NONE: str = "none"; break;
1804     case SCAMPER_SNIFF_STOP_ERROR: str = "error"; break;
1805     case SCAMPER_SNIFF_STOP_LIMIT_TIME: str = "limit-time"; break;
1806     case SCAMPER_SNIFF_STOP_LIMIT_PKTC: str = "limit-pktc"; break;
1807     case SCAMPER_SNIFF_STOP_HALTED: str = "halted"; break;
1808     default:
1809       snprintf(buf, sizeof(buf), "%d", sniff->stop_reason);
1810       str = buf;
1811       break;
1812     }
1813   printf(" result: %s, pktc: %d\n", str, sniff->pktc);
1814 
1815   for(i=0; i<sniff->pktc; i++)
1816     {
1817       pkt = sniff->pkts[i];
1818       timeval_diff_tv(&tv, &sniff->start, &pkt->tv);
1819       printf(" %3d %d.%06d", i, (int)tv.tv_sec, (int)tv.tv_usec);
1820       u8 = (pkt->data[0] & 0xf0) >> 4;
1821       if(u8 == 4)
1822 	{
1823 	  printf(" %s -> %s",
1824 		 inet_ntop(AF_INET, pkt->data+12, src, sizeof(src)),
1825 		 inet_ntop(AF_INET, pkt->data+16, dst, sizeof(dst)));
1826 	}
1827       else if(u8 == 6)
1828 	{
1829 	  printf(" %s -> %s",
1830 		 inet_ntop(AF_INET6, pkt->data+8,  src, sizeof(src)),
1831 		 inet_ntop(AF_INET6, pkt->data+24, dst, sizeof(dst)));
1832 	}
1833       printf("\n");
1834 
1835       ptr = pkt->data;
1836       for(j=0; j+16<=pkt->len; j+=16)
1837 	{
1838 	  printf("     0x%04x: ", j);
1839 	  for(k=0; k<8; k++)
1840 	    {
1841 	      printf(" %02x%02x", ptr[0], ptr[1]);
1842 	      ptr += 2;
1843 	    }
1844 	  printf("\n");
1845 	}
1846       if(pkt->len - j != 0)
1847 	{
1848 	  printf("     0x%04x: ", j);
1849 	  while(j<pkt->len)
1850 	    {
1851 	      if((j % 2) == 0)
1852 		printf(" ");
1853 	      printf("%02x", *ptr);
1854 	      ptr++;
1855 	      j++;
1856 	    }
1857 	  printf("\n");
1858 	}
1859     }
1860 
1861   return;
1862 }
1863 
dump_host_rr(scamper_host_rr_t * rr,const char * section)1864 static void dump_host_rr(scamper_host_rr_t *rr, const char *section)
1865 {
1866   char buf[256];
1867 
1868   printf("  %s: %s %u ", section,
1869 	 rr->name != NULL ? rr->name : "<null>", rr->ttl);
1870 
1871   if(rr->class == SCAMPER_HOST_CLASS_IN)
1872     printf("IN");
1873   else
1874     printf("%d", rr->class);
1875   printf(" ");
1876   switch(rr->type)
1877     {
1878     case SCAMPER_HOST_TYPE_A: printf("A"); break;
1879     case SCAMPER_HOST_TYPE_NS: printf("NS"); break;
1880     case SCAMPER_HOST_TYPE_CNAME: printf("CNAME"); break;
1881     case SCAMPER_HOST_TYPE_SOA: printf("SOA"); break;
1882     case SCAMPER_HOST_TYPE_PTR: printf("PTR"); break;
1883     case SCAMPER_HOST_TYPE_MX: printf("MX"); break;
1884     case SCAMPER_HOST_TYPE_TXT: printf("TXT"); break;
1885     case SCAMPER_HOST_TYPE_AAAA: printf("AAAA"); break;
1886     case SCAMPER_HOST_TYPE_DS: printf("DS"); break;
1887     case SCAMPER_HOST_TYPE_SSHFP: printf("SSHFP"); break;
1888     case SCAMPER_HOST_TYPE_RRSIG: printf("RRISG"); break;
1889     case SCAMPER_HOST_TYPE_NSEC: printf("NSEC"); break;
1890     case SCAMPER_HOST_TYPE_DNSKEY: printf("DNSKEY"); break;
1891     default: printf("%d", rr->type); break;
1892     }
1893 
1894   switch(scamper_host_rr_data_type(rr->class, rr->type))
1895     {
1896     case SCAMPER_HOST_RR_DATA_TYPE_ADDR:
1897       printf(" %s", scamper_addr_tostr(rr->un.addr, buf, sizeof(buf)));
1898       break;
1899 
1900     case SCAMPER_HOST_RR_DATA_TYPE_STR:
1901       printf(" %s", rr->un.str);
1902       break;
1903 
1904     case SCAMPER_HOST_RR_DATA_TYPE_MX:
1905       printf(" %d %s", rr->un.mx->preference, rr->un.mx->exchange);
1906       break;
1907     }
1908 
1909   printf("\n");
1910   return;
1911 }
1912 
dump_host(scamper_host_t * host)1913 static void dump_host(scamper_host_t *host)
1914 {
1915   scamper_host_query_t *query;
1916   struct timeval tv;
1917   char buf[256];
1918   uint32_t i, j;
1919 
1920   printf("host");
1921   if(host->src != NULL)
1922     printf(" from %s", scamper_addr_tostr(host->src, buf, sizeof(buf)));
1923   printf(" to %s\n", scamper_addr_tostr(host->dst, buf, sizeof(buf)));
1924   dump_list_summary(host->list);
1925   dump_cycle_summary(host->cycle);
1926   printf(" user-id: %d\n", host->userid);
1927   dump_timeval("start", &host->start);
1928 
1929   if(host->flags != 0)
1930     {
1931       printf(" flags: ");
1932       if(host->flags & SCAMPER_HOST_FLAG_NORECURSE)
1933 	printf("norecurse");
1934       printf("\n");
1935     }
1936 
1937   printf(" wait: %ums, retries: %u\n", host->wait, host->retries);
1938   printf(" stop: ");
1939   switch(host->stop)
1940     {
1941     case SCAMPER_HOST_STOP_NONE: printf("none"); break;
1942     case SCAMPER_HOST_STOP_DONE: printf("done"); break;
1943     case SCAMPER_HOST_STOP_TIMEOUT: printf("timeout"); break;
1944     case SCAMPER_HOST_STOP_HALTED: printf("halted"); break;
1945     case SCAMPER_HOST_STOP_ERROR: printf("error"); break;
1946     default: printf("%04x", host->stop); break;
1947     }
1948   printf("\n");
1949 
1950   printf(" qname: %s, qclass: ", host->qname);
1951   if(host->qclass == SCAMPER_HOST_CLASS_IN)
1952     printf("IN");
1953   else
1954     printf("%d", host->qclass);
1955 
1956   printf(", qtype: ");
1957   switch(host->qtype)
1958     {
1959     case SCAMPER_HOST_TYPE_A: printf("A"); break;
1960     case SCAMPER_HOST_TYPE_NS: printf("NS"); break;
1961     case SCAMPER_HOST_TYPE_CNAME: printf("CNAME"); break;
1962     case SCAMPER_HOST_TYPE_SOA: printf("SOA"); break;
1963     case SCAMPER_HOST_TYPE_PTR: printf("PTR"); break;
1964     case SCAMPER_HOST_TYPE_MX: printf("MX"); break;
1965     case SCAMPER_HOST_TYPE_TXT: printf("TXT"); break;
1966     case SCAMPER_HOST_TYPE_AAAA: printf("AAAA"); break;
1967     case SCAMPER_HOST_TYPE_DS: printf("DS"); break;
1968     case SCAMPER_HOST_TYPE_SSHFP: printf("SSHFP"); break;
1969     case SCAMPER_HOST_TYPE_RRSIG: printf("RRSIG"); break;
1970     case SCAMPER_HOST_TYPE_NSEC: printf("NSEC"); break;
1971     case SCAMPER_HOST_TYPE_DNSKEY: printf("DNSKEY"); break;
1972     default: printf("%04x", host->qtype); break;
1973     }
1974   printf("\n");
1975   printf(" qcount: %d\n", host->qcount);
1976 
1977   for(i=0; i<host->qcount; i++)
1978     {
1979       query = host->queries[i];
1980       timeval_diff_tv(&tv, &host->start, &query->tx);
1981       printf(" query: %u, id: %u, tx: %d.%06d", i, query->id,
1982 	     (int)tv.tv_sec, (int)tv.tv_usec);
1983       timeval_diff_tv(&tv, &query->tx, &query->rx);
1984       printf(", rtt: %d.%06d", (int)tv.tv_sec, (int)tv.tv_usec);
1985       printf(", an: %u, ns: %u, ar: %u", query->ancount, query->nscount,
1986 	     query->arcount);
1987       printf("\n");
1988 
1989       for(j=0; j<query->ancount; j++)
1990 	dump_host_rr(query->an[j], "an");
1991       for(j=0; j<query->nscount; j++)
1992 	dump_host_rr(query->ns[j], "ns");
1993       for(j=0; j<query->arcount; j++)
1994 	dump_host_rr(query->ar[j], "ar");
1995     }
1996 
1997   printf("\n");
1998   return;
1999 }
2000 
dump_cycle(scamper_cycle_t * cycle,const char * type)2001 static void dump_cycle(scamper_cycle_t *cycle, const char *type)
2002 {
2003   time_t tt;
2004   char buf[32];
2005 
2006   if(strcmp(type, "start") == 0 || strcmp(type, "def") == 0)
2007     tt = cycle->start_time;
2008   else
2009     tt = cycle->stop_time;
2010 
2011   memcpy(buf, ctime(&tt), 24); buf[24] = '\0';
2012 
2013   printf("cycle %s, list %s %d, cycle %d, time %s\n",
2014 	 type, cycle->list->name, cycle->list->id, cycle->id, buf);
2015   scamper_cycle_free(cycle);
2016   return;
2017 }
2018 
dump_list(scamper_list_t * list)2019 static void dump_list(scamper_list_t *list)
2020 {
2021   printf("list id %d, name %s", list->id, list->name);
2022   if(list->descr != NULL) printf(", descr \"%s\"", list->descr);
2023   printf("\n");
2024   scamper_list_free(list);
2025   return;
2026 }
2027 
dump_addr(scamper_addr_t * addr)2028 static void dump_addr(scamper_addr_t *addr)
2029 {
2030   char buf[128];
2031   printf("addr %s\n", scamper_addr_tostr(addr, buf, sizeof(buf)));
2032   scamper_addr_free(addr);
2033   return;
2034 }
2035 
main(int argc,char * argv[])2036 int main(int argc, char *argv[])
2037 {
2038   scamper_file_t        *file;
2039   scamper_file_filter_t *filter;
2040   uint16_t filter_types[] = {
2041     SCAMPER_FILE_OBJ_LIST,
2042     SCAMPER_FILE_OBJ_CYCLE_START,
2043     SCAMPER_FILE_OBJ_CYCLE_DEF,
2044     SCAMPER_FILE_OBJ_CYCLE_STOP,
2045     SCAMPER_FILE_OBJ_TRACE,
2046     SCAMPER_FILE_OBJ_PING,
2047     SCAMPER_FILE_OBJ_TRACELB,
2048     SCAMPER_FILE_OBJ_DEALIAS,
2049     SCAMPER_FILE_OBJ_NEIGHBOURDISC,
2050     SCAMPER_FILE_OBJ_TBIT,
2051     SCAMPER_FILE_OBJ_STING,
2052     SCAMPER_FILE_OBJ_SNIFF,
2053     SCAMPER_FILE_OBJ_HOST,
2054   };
2055   uint16_t filter_cnt = sizeof(filter_types)/sizeof(uint16_t);
2056   void     *data;
2057   uint16_t  type;
2058   int       f;
2059 
2060 #ifdef _WIN32
2061   WSADATA wsaData;
2062   WSAStartup(MAKEWORD(2,2), &wsaData);
2063 #endif
2064 
2065 #if defined(DMALLOC)
2066   free(malloc(1));
2067 #endif
2068 
2069   if((filter = scamper_file_filter_alloc(filter_types, filter_cnt)) == NULL)
2070     {
2071       usage();
2072       fprintf(stderr, "could not alloc filter\n");
2073       return -1;
2074     }
2075 
2076   for(f=0; f<argc; f++)
2077     {
2078       if(f == 0)
2079 	{
2080 	  if(argc > 1)
2081 	    continue;
2082 
2083 	  if((file=scamper_file_openfd(STDIN_FILENO,"-",'r',"warts")) == NULL)
2084 	    {
2085 	      usage();
2086 	      fprintf(stderr, "could not use stdin\n");
2087 	      return -1;
2088 	    }
2089 	}
2090       else
2091 	{
2092 	  if((file = scamper_file_open(argv[f], 'r', NULL)) == NULL)
2093 	    {
2094 	      usage();
2095 	      fprintf(stderr, "could not open %s\n", argv[f]);
2096 	      return -1;
2097 	    }
2098 	}
2099 
2100       while(scamper_file_read(file, filter, &type, &data) == 0)
2101 	{
2102 	  /* hit eof */
2103 	  if(data == NULL)
2104 	    goto done;
2105 
2106 	  switch(type)
2107 	    {
2108 	    case SCAMPER_FILE_OBJ_ADDR:
2109 	      dump_addr(data);
2110 	      break;
2111 
2112 	    case SCAMPER_FILE_OBJ_TRACE:
2113 	      dump_trace(data);
2114 	      break;
2115 
2116 	    case SCAMPER_FILE_OBJ_PING:
2117 	      dump_ping(data);
2118 	      break;
2119 
2120 	    case SCAMPER_FILE_OBJ_TRACELB:
2121 	      dump_tracelb(data);
2122 	      break;
2123 
2124 	    case SCAMPER_FILE_OBJ_DEALIAS:
2125 	      dump_dealias(data);
2126 	      break;
2127 
2128 	    case SCAMPER_FILE_OBJ_NEIGHBOURDISC:
2129 	      dump_neighbourdisc(data);
2130 	      break;
2131 
2132 	    case SCAMPER_FILE_OBJ_TBIT:
2133 	      dump_tbit(data);
2134 	      break;
2135 
2136 	    case SCAMPER_FILE_OBJ_STING:
2137 	      dump_sting(data);
2138 	      break;
2139 
2140 	    case SCAMPER_FILE_OBJ_SNIFF:
2141 	      dump_sniff(data);
2142 	      break;
2143 
2144 	    case SCAMPER_FILE_OBJ_HOST:
2145 	      dump_host(data);
2146 	      break;
2147 
2148 	    case SCAMPER_FILE_OBJ_LIST:
2149 	      dump_list(data);
2150 	      break;
2151 
2152 	    case SCAMPER_FILE_OBJ_CYCLE_START:
2153 	      dump_cycle(data, "start");
2154 	      break;
2155 
2156 	    case SCAMPER_FILE_OBJ_CYCLE_STOP:
2157 	      dump_cycle(data, "stop");
2158 	      break;
2159 
2160 	    case SCAMPER_FILE_OBJ_CYCLE_DEF:
2161 	      dump_cycle(data, "def");
2162 	      break;
2163 	    }
2164 	}
2165 
2166     done:
2167       scamper_file_close(file);
2168 
2169       if(argc == 1)
2170 	break;
2171     }
2172 
2173   scamper_file_filter_free(filter);
2174   return 0;
2175 }
2176