10f66f451Sopenharmony_ci/* traceroute - trace the route to "host". 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2012 Madhur Verma <mad.flexi@gmail.com> 40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com> 50f66f451Sopenharmony_ci * Copyright 2013 Bilal Qureshi <bilal.jmi@gmail.com> 60f66f451Sopenharmony_ci * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com> 70f66f451Sopenharmony_ci * 80f66f451Sopenharmony_ci * No Standard 90f66f451Sopenharmony_ci 100f66f451Sopenharmony_ciUSE_TRACEROUTE(NEWTOY(traceroute, "<1>2i:f#<1>255=1z#<0>86400=0g*w#<0>86400=5t#<0>255=0s:q#<1>255=3p#<1>65535=33434m#<1>255=30rvndlIUF64", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) 110f66f451Sopenharmony_ciUSE_TRACEROUTE(OLDTOY(traceroute6,traceroute, TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN)) 120f66f451Sopenharmony_ciconfig TRACEROUTE 130f66f451Sopenharmony_ci bool "traceroute" 140f66f451Sopenharmony_ci default n 150f66f451Sopenharmony_ci help 160f66f451Sopenharmony_ci usage: traceroute [-46FUIldnvr] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES] 170f66f451Sopenharmony_ci [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE] [-z PAUSE_MSEC] HOST [BYTES] 180f66f451Sopenharmony_ci 190f66f451Sopenharmony_ci traceroute6 [-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES][-s SRC_IP] [-t TOS] [-w WAIT_SEC] 200f66f451Sopenharmony_ci [-i IFACE] HOST [BYTES] 210f66f451Sopenharmony_ci 220f66f451Sopenharmony_ci Trace the route to HOST 230f66f451Sopenharmony_ci 240f66f451Sopenharmony_ci -4,-6 Force IP or IPv6 name resolution 250f66f451Sopenharmony_ci -F Set the don't fragment bit (supports IPV4 only) 260f66f451Sopenharmony_ci -U Use UDP datagrams instead of ICMP ECHO (supports IPV4 only) 270f66f451Sopenharmony_ci -I Use ICMP ECHO instead of UDP datagrams (supports IPV4 only) 280f66f451Sopenharmony_ci -l Display the TTL value of the returned packet (supports IPV4 only) 290f66f451Sopenharmony_ci -d Set SO_DEBUG options to socket 300f66f451Sopenharmony_ci -n Print numeric addresses 310f66f451Sopenharmony_ci -v verbose 320f66f451Sopenharmony_ci -r Bypass routing tables, send directly to HOST 330f66f451Sopenharmony_ci -m Max time-to-live (max number of hops)(RANGE 1 to 255) 340f66f451Sopenharmony_ci -p Base UDP port number used in probes(default 33434)(RANGE 1 to 65535) 350f66f451Sopenharmony_ci -q Number of probes per TTL (default 3)(RANGE 1 to 255) 360f66f451Sopenharmony_ci -s IP address to use as the source address 370f66f451Sopenharmony_ci -t Type-of-service in probe packets (default 0)(RANGE 0 to 255) 380f66f451Sopenharmony_ci -w Time in seconds to wait for a response (default 3)(RANGE 0 to 86400) 390f66f451Sopenharmony_ci -g Loose source route gateway (8 max) (supports IPV4 only) 400f66f451Sopenharmony_ci -z Pause Time in ms (default 0)(RANGE 0 to 86400) (supports IPV4 only) 410f66f451Sopenharmony_ci -f Start from the 1ST_TTL hop (instead from 1)(RANGE 1 to 255) (supports IPV4 only) 420f66f451Sopenharmony_ci -i Specify a network interface to operate with 430f66f451Sopenharmony_ci*/ 440f66f451Sopenharmony_ci#define FOR_traceroute 450f66f451Sopenharmony_ci#include "toys.h" 460f66f451Sopenharmony_ci#include <netinet/udp.h> 470f66f451Sopenharmony_ci#include <netinet/ip_icmp.h> 480f66f451Sopenharmony_ci#include <netinet/ip6.h> 490f66f451Sopenharmony_ci#include <netinet/icmp6.h> 500f66f451Sopenharmony_ci 510f66f451Sopenharmony_ciGLOBALS( 520f66f451Sopenharmony_ci long max_ttl; 530f66f451Sopenharmony_ci long port; 540f66f451Sopenharmony_ci long ttl_probes; 550f66f451Sopenharmony_ci char *src_ip; 560f66f451Sopenharmony_ci long tos; 570f66f451Sopenharmony_ci long wait_time; 580f66f451Sopenharmony_ci struct arg_list *loose_source; 590f66f451Sopenharmony_ci long pause_time; 600f66f451Sopenharmony_ci long first_ttl; 610f66f451Sopenharmony_ci char *iface; 620f66f451Sopenharmony_ci 630f66f451Sopenharmony_ci uint32_t gw_list[9]; 640f66f451Sopenharmony_ci int recv_sock; 650f66f451Sopenharmony_ci int snd_sock; 660f66f451Sopenharmony_ci unsigned msg_len; 670f66f451Sopenharmony_ci char *packet; 680f66f451Sopenharmony_ci uint32_t ident; 690f66f451Sopenharmony_ci int istraceroute6; 700f66f451Sopenharmony_ci) 710f66f451Sopenharmony_ci 720f66f451Sopenharmony_ci#ifndef SOL_IPV6 730f66f451Sopenharmony_ci# define SOL_IPV6 IPPROTO_IPV6 740f66f451Sopenharmony_ci#endif 750f66f451Sopenharmony_ci 760f66f451Sopenharmony_ci#define ICMP_HD_SIZE4 8 770f66f451Sopenharmony_ci#define USEC 1000000ULL 780f66f451Sopenharmony_ci 790f66f451Sopenharmony_cistruct payload_s { 800f66f451Sopenharmony_ci uint32_t seq; 810f66f451Sopenharmony_ci uint32_t ident; 820f66f451Sopenharmony_ci}; 830f66f451Sopenharmony_ci 840f66f451Sopenharmony_cichar addr_str[INET6_ADDRSTRLEN]; 850f66f451Sopenharmony_cistruct sockaddr_storage dest; 860f66f451Sopenharmony_ci 870f66f451Sopenharmony_ci//Compute checksum SUM of buffer P of length LEN 880f66f451Sopenharmony_cistatic u_int16_t in_cksum(u_int16_t *p, u_int len) 890f66f451Sopenharmony_ci{ 900f66f451Sopenharmony_ci u_int32_t sum = 0; 910f66f451Sopenharmony_ci int nwords = len >> 1; 920f66f451Sopenharmony_ci 930f66f451Sopenharmony_ci while (nwords-- != 0) sum += *p++; 940f66f451Sopenharmony_ci if (len & 1) { 950f66f451Sopenharmony_ci union { 960f66f451Sopenharmony_ci u_int16_t w; 970f66f451Sopenharmony_ci u_int8_t c[2]; 980f66f451Sopenharmony_ci } u; 990f66f451Sopenharmony_ci u.c[0] = *(u_char *) p; 1000f66f451Sopenharmony_ci u.c[1] = 0; 1010f66f451Sopenharmony_ci sum += u.w; 1020f66f451Sopenharmony_ci } 1030f66f451Sopenharmony_ci // end-around-carry 1040f66f451Sopenharmony_ci sum = (sum >> 16) + (sum & 0xffff); 1050f66f451Sopenharmony_ci sum += (sum >> 16); 1060f66f451Sopenharmony_ci return (~sum); 1070f66f451Sopenharmony_ci} 1080f66f451Sopenharmony_ci 1090f66f451Sopenharmony_ci//sends a single probe packet with sequence(SEQ) and time-to-live(TTL) 1100f66f451Sopenharmony_cistatic void send_probe4(int seq, int ttl) 1110f66f451Sopenharmony_ci{ 1120f66f451Sopenharmony_ci int res, len; 1130f66f451Sopenharmony_ci void *out; 1140f66f451Sopenharmony_ci struct payload_s *send_data4 = (struct payload_s *)(TT.packet); 1150f66f451Sopenharmony_ci struct icmp *send_icmp4 = (struct icmp *)(TT.packet); 1160f66f451Sopenharmony_ci 1170f66f451Sopenharmony_ci if (toys.optflags & FLAG_U) { 1180f66f451Sopenharmony_ci send_data4->seq = seq; 1190f66f451Sopenharmony_ci send_data4->ident = TT.ident; 1200f66f451Sopenharmony_ci ((struct sockaddr_in *)&dest)->sin_port = TT.port + seq; 1210f66f451Sopenharmony_ci out = send_data4; 1220f66f451Sopenharmony_ci } else { 1230f66f451Sopenharmony_ci send_icmp4->icmp_type = ICMP_ECHO; 1240f66f451Sopenharmony_ci send_icmp4->icmp_id = htons(TT.ident); 1250f66f451Sopenharmony_ci send_icmp4->icmp_seq = htons(seq); 1260f66f451Sopenharmony_ci send_icmp4->icmp_cksum = 0; 1270f66f451Sopenharmony_ci send_icmp4->icmp_cksum = in_cksum((uint16_t *) send_icmp4, TT.msg_len); 1280f66f451Sopenharmony_ci if (send_icmp4->icmp_cksum == 0) send_icmp4->icmp_cksum = 0xffff; 1290f66f451Sopenharmony_ci out = send_icmp4; 1300f66f451Sopenharmony_ci } 1310f66f451Sopenharmony_ci 1320f66f451Sopenharmony_ci res = setsockopt(TT.snd_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); 1330f66f451Sopenharmony_ci if (res < 0) perror_exit("setsockopt ttl %d", ttl); 1340f66f451Sopenharmony_ci 1350f66f451Sopenharmony_ci len = TT.msg_len; 1360f66f451Sopenharmony_ci res = sendto(TT.snd_sock, out, len, 0, (struct sockaddr *) &dest, 1370f66f451Sopenharmony_ci sizeof(struct sockaddr_in)); 1380f66f451Sopenharmony_ci if (res != len) perror_exit(" sendto"); 1390f66f451Sopenharmony_ci} 1400f66f451Sopenharmony_ci 1410f66f451Sopenharmony_ci//sends a single probe packet with sequence(SEQ) and time-to-live(TTL) 1420f66f451Sopenharmony_cistatic void send_probe6(int seq, int ttl) 1430f66f451Sopenharmony_ci{ 1440f66f451Sopenharmony_ci void *out; 1450f66f451Sopenharmony_ci struct payload_s *send_data6 = (struct payload_s *) (TT.packet); 1460f66f451Sopenharmony_ci 1470f66f451Sopenharmony_ci send_data6->seq = seq; 1480f66f451Sopenharmony_ci send_data6->ident = TT.ident; 1490f66f451Sopenharmony_ci ((struct sockaddr_in6 *)&dest)->sin6_port = TT.port; 1500f66f451Sopenharmony_ci 1510f66f451Sopenharmony_ci if (setsockopt(TT.snd_sock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, 1520f66f451Sopenharmony_ci sizeof(ttl)) < 0) error_exit("setsockopt ttl %d", ttl); 1530f66f451Sopenharmony_ci 1540f66f451Sopenharmony_ci out = send_data6; 1550f66f451Sopenharmony_ci 1560f66f451Sopenharmony_ci if (sendto(TT.snd_sock, out, TT.msg_len, 0, 1570f66f451Sopenharmony_ci (struct sockaddr *) &dest, sizeof(struct sockaddr_in6)) < 0) 1580f66f451Sopenharmony_ci perror_exit("sendto"); 1590f66f451Sopenharmony_ci} 1600f66f451Sopenharmony_ci 1610f66f451Sopenharmony_cistatic void set_flag_dr(int sock) 1620f66f451Sopenharmony_ci{ 1630f66f451Sopenharmony_ci int set = 1; 1640f66f451Sopenharmony_ci if ((toys.optflags & FLAG_d) && (setsockopt(sock,SOL_SOCKET, SO_DEBUG, 1650f66f451Sopenharmony_ci &set, sizeof(set)) < 0)) perror_exit("SO_DEBUG failed "); 1660f66f451Sopenharmony_ci 1670f66f451Sopenharmony_ci if ((toys.optflags & FLAG_r) && (setsockopt(sock, SOL_SOCKET, SO_DONTROUTE, 1680f66f451Sopenharmony_ci &set, sizeof(set)) < 0)) perror_exit("SO_DONTROUTE failed "); 1690f66f451Sopenharmony_ci} 1700f66f451Sopenharmony_ci 1710f66f451Sopenharmony_cistatic void bind_to_interface(int sock) 1720f66f451Sopenharmony_ci{ 1730f66f451Sopenharmony_ci struct ifreq ifr; 1740f66f451Sopenharmony_ci 1750f66f451Sopenharmony_ci snprintf(ifr.ifr_name, IFNAMSIZ, "%s", TT.iface); 1760f66f451Sopenharmony_ci if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) 1770f66f451Sopenharmony_ci perror_msg("can't bind to interface %s", TT.iface); 1780f66f451Sopenharmony_ci} 1790f66f451Sopenharmony_ci 1800f66f451Sopenharmony_cistatic void resolve_addr(char *host, int family, int type, int proto, void *sock) 1810f66f451Sopenharmony_ci{ 1820f66f451Sopenharmony_ci struct addrinfo *info, hint; 1830f66f451Sopenharmony_ci int ret; 1840f66f451Sopenharmony_ci 1850f66f451Sopenharmony_ci memset(&hint, 0, sizeof(hint)); 1860f66f451Sopenharmony_ci hint.ai_family = family; 1870f66f451Sopenharmony_ci hint.ai_socktype = type; 1880f66f451Sopenharmony_ci hint.ai_protocol = proto; 1890f66f451Sopenharmony_ci 1900f66f451Sopenharmony_ci ret = getaddrinfo(host, NULL, &hint, &info); 1910f66f451Sopenharmony_ci if (ret || !info) error_exit("bad address: %s ", host); 1920f66f451Sopenharmony_ci 1930f66f451Sopenharmony_ci memcpy(sock, info->ai_addr, info->ai_addrlen); 1940f66f451Sopenharmony_ci freeaddrinfo(info); 1950f66f451Sopenharmony_ci} 1960f66f451Sopenharmony_ci 1970f66f451Sopenharmony_cistatic void do_trace() 1980f66f451Sopenharmony_ci{ 1990f66f451Sopenharmony_ci int seq, fexit, ttl, tv = TT.wait_time * 1000; 2000f66f451Sopenharmony_ci struct pollfd pfd[1]; 2010f66f451Sopenharmony_ci struct sockaddr_storage from; 2020f66f451Sopenharmony_ci 2030f66f451Sopenharmony_ci memset(&from, 0, sizeof(from)); 2040f66f451Sopenharmony_ci pfd[0].fd = TT.recv_sock; 2050f66f451Sopenharmony_ci pfd[0].events = POLLIN; 2060f66f451Sopenharmony_ci 2070f66f451Sopenharmony_ci for (ttl = TT.first_ttl; ttl <= TT.max_ttl; ++ttl) { 2080f66f451Sopenharmony_ci int probe, dest_reach = 0, print_verbose = 1; 2090f66f451Sopenharmony_ci struct timeval t1, t2; 2100f66f451Sopenharmony_ci struct sockaddr_storage last_addr; 2110f66f451Sopenharmony_ci 2120f66f451Sopenharmony_ci memset(&last_addr, 0, sizeof(last_addr)); 2130f66f451Sopenharmony_ci fexit = 0; 2140f66f451Sopenharmony_ci xprintf("%2d", ttl); 2150f66f451Sopenharmony_ci 2160f66f451Sopenharmony_ci for (probe = 0, seq = 0; probe < TT.ttl_probes; ++probe) { 2170f66f451Sopenharmony_ci int res = 0, tleft; 2180f66f451Sopenharmony_ci 2190f66f451Sopenharmony_ci fflush(NULL); 2200f66f451Sopenharmony_ci if (!TT.istraceroute6) 2210f66f451Sopenharmony_ci if (probe && (toys.optflags & FLAG_z)) msleep(TT.pause_time); 2220f66f451Sopenharmony_ci 2230f66f451Sopenharmony_ci if (!TT.istraceroute6) send_probe4(++seq, ttl); 2240f66f451Sopenharmony_ci else send_probe6(++seq, ttl); 2250f66f451Sopenharmony_ci gettimeofday(&t1, NULL); 2260f66f451Sopenharmony_ci t2 = t1; 2270f66f451Sopenharmony_ci 2280f66f451Sopenharmony_ci while ((tleft = (int)(tv - ((unsigned long long)(t2.tv_sec * 1000ULL 2290f66f451Sopenharmony_ci + t2.tv_usec/1000) - (unsigned long long)(t1.tv_sec * 1000ULL 2300f66f451Sopenharmony_ci + t1.tv_usec/1000)))) >= 0) { 2310f66f451Sopenharmony_ci unsigned delta = 0; 2320f66f451Sopenharmony_ci if (!(res = poll(pfd, 1, tleft))) { 2330f66f451Sopenharmony_ci xprintf(" *"); 2340f66f451Sopenharmony_ci break; 2350f66f451Sopenharmony_ci } 2360f66f451Sopenharmony_ci gettimeofday(&t2, NULL); 2370f66f451Sopenharmony_ci if (res < 0) { 2380f66f451Sopenharmony_ci if (errno != EINTR) perror_exit("poll"); 2390f66f451Sopenharmony_ci continue; 2400f66f451Sopenharmony_ci } 2410f66f451Sopenharmony_ci delta = (t2.tv_sec * USEC + t2.tv_usec) 2420f66f451Sopenharmony_ci - (t1.tv_sec * USEC + t1.tv_usec); 2430f66f451Sopenharmony_ci 2440f66f451Sopenharmony_ci if (pfd[0].revents) { 2450f66f451Sopenharmony_ci socklen_t addrlen = sizeof(struct sockaddr_storage); 2460f66f451Sopenharmony_ci int rcv_len, icmp_res = 0; 2470f66f451Sopenharmony_ci 2480f66f451Sopenharmony_ci rcv_len = recvfrom(TT.recv_sock, toybuf, sizeof(toybuf), 2490f66f451Sopenharmony_ci MSG_DONTWAIT, (struct sockaddr *) &from, &addrlen); 2500f66f451Sopenharmony_ci if (rcv_len <= 0) continue; 2510f66f451Sopenharmony_ci 2520f66f451Sopenharmony_ci if (!TT.istraceroute6) { 2530f66f451Sopenharmony_ci int pmtu = 0; 2540f66f451Sopenharmony_ci struct ip *rcv_pkt = (struct ip*) toybuf; 2550f66f451Sopenharmony_ci struct icmp *ricmp; 2560f66f451Sopenharmony_ci 2570f66f451Sopenharmony_ci ricmp = (struct icmp *) ((char*)rcv_pkt + (rcv_pkt->ip_hl << 2)); 2580f66f451Sopenharmony_ci if (ricmp->icmp_code == ICMP_UNREACH_NEEDFRAG) 2590f66f451Sopenharmony_ci pmtu = ntohs(ricmp->icmp_nextmtu); 2600f66f451Sopenharmony_ci 2610f66f451Sopenharmony_ci if ((ricmp->icmp_type == ICMP_TIMXCEED 2620f66f451Sopenharmony_ci && ricmp->icmp_code == ICMP_TIMXCEED_INTRANS) 2630f66f451Sopenharmony_ci || ricmp->icmp_type == ICMP_UNREACH 2640f66f451Sopenharmony_ci || ricmp->icmp_type == ICMP_ECHOREPLY) { 2650f66f451Sopenharmony_ci 2660f66f451Sopenharmony_ci struct udphdr *hudp; 2670f66f451Sopenharmony_ci struct icmp *hicmp; 2680f66f451Sopenharmony_ci struct ip *hip = &ricmp->icmp_ip; 2690f66f451Sopenharmony_ci 2700f66f451Sopenharmony_ci if (toys.optflags & FLAG_U) { 2710f66f451Sopenharmony_ci hudp = (struct udphdr*) ((char*)hip + (hip->ip_hl << 2)); 2720f66f451Sopenharmony_ci if ((hip->ip_hl << 2) + 12 <=(rcv_len - (rcv_pkt->ip_hl << 2)) 2730f66f451Sopenharmony_ci && hip->ip_p == IPPROTO_UDP 2740f66f451Sopenharmony_ci && hudp->dest == (TT.port + seq)) 2750f66f451Sopenharmony_ci icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 : 2760f66f451Sopenharmony_ci ricmp->icmp_code); 2770f66f451Sopenharmony_ci } else { 2780f66f451Sopenharmony_ci hicmp = (struct icmp *) ((char*)hip + (hip->ip_hl << 2)); 2790f66f451Sopenharmony_ci if (ricmp->icmp_type == ICMP_ECHOREPLY 2800f66f451Sopenharmony_ci && ricmp->icmp_id == ntohs(TT.ident) 2810f66f451Sopenharmony_ci && ricmp->icmp_seq == ntohs(seq)) 2820f66f451Sopenharmony_ci icmp_res = ICMP_UNREACH_PORT; 2830f66f451Sopenharmony_ci else if ((hip->ip_hl << 2) + ICMP_HD_SIZE4 2840f66f451Sopenharmony_ci <= (rcv_len - (rcv_pkt->ip_hl << 2)) 2850f66f451Sopenharmony_ci && hip->ip_p == IPPROTO_ICMP 2860f66f451Sopenharmony_ci && hicmp->icmp_id == htons(TT.ident) 2870f66f451Sopenharmony_ci && hicmp->icmp_seq == htons(seq)) 2880f66f451Sopenharmony_ci icmp_res = (ricmp->icmp_type == ICMP_TIMXCEED ? -1 : 2890f66f451Sopenharmony_ci ricmp->icmp_code); 2900f66f451Sopenharmony_ci } 2910f66f451Sopenharmony_ci } 2920f66f451Sopenharmony_ci if (!icmp_res) continue; 2930f66f451Sopenharmony_ci 2940f66f451Sopenharmony_ci if (addrlen > 0) { 2950f66f451Sopenharmony_ci if (memcmp(&((struct sockaddr_in *)&last_addr)->sin_addr, 2960f66f451Sopenharmony_ci &((struct sockaddr_in *)&from)->sin_addr, 2970f66f451Sopenharmony_ci sizeof(struct in_addr))) { 2980f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_n)) { 2990f66f451Sopenharmony_ci char host[NI_MAXHOST]; 3000f66f451Sopenharmony_ci if (!getnameinfo((struct sockaddr *) &from, 3010f66f451Sopenharmony_ci sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, 0)) 3020f66f451Sopenharmony_ci xprintf(" %s (", host); 3030f66f451Sopenharmony_ci else xprintf(" %s (", inet_ntoa( 3040f66f451Sopenharmony_ci ((struct sockaddr_in *)&from)->sin_addr)); 3050f66f451Sopenharmony_ci } 3060f66f451Sopenharmony_ci xprintf(" %s", inet_ntoa( 3070f66f451Sopenharmony_ci ((struct sockaddr_in *)&from)->sin_addr)); 3080f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_n)) xprintf(")"); 3090f66f451Sopenharmony_ci memcpy(&last_addr, &from, sizeof(from)); 3100f66f451Sopenharmony_ci } 3110f66f451Sopenharmony_ci xprintf(" %u.%03u ms", delta / 1000, delta % 1000); 3120f66f451Sopenharmony_ci if (toys.optflags & FLAG_l) xprintf(" (%d)", rcv_pkt->ip_ttl); 3130f66f451Sopenharmony_ci if (toys.optflags & FLAG_v) { 3140f66f451Sopenharmony_ci xprintf(" %d bytes from %s : icmp type %d code %d\t", 3150f66f451Sopenharmony_ci rcv_len, inet_ntoa(((struct sockaddr_in *)&from)->sin_addr), 3160f66f451Sopenharmony_ci ricmp->icmp_type, ricmp->icmp_code); 3170f66f451Sopenharmony_ci } 3180f66f451Sopenharmony_ci } else xprintf("\t!H"); 3190f66f451Sopenharmony_ci 3200f66f451Sopenharmony_ci switch (icmp_res) { 3210f66f451Sopenharmony_ci case ICMP_UNREACH_PORT: 3220f66f451Sopenharmony_ci if (rcv_pkt->ip_ttl <= 1) xprintf(" !"); 3230f66f451Sopenharmony_ci dest_reach = 1; 3240f66f451Sopenharmony_ci break; 3250f66f451Sopenharmony_ci case ICMP_UNREACH_NET: 3260f66f451Sopenharmony_ci xprintf(" !N"); 3270f66f451Sopenharmony_ci ++fexit; 3280f66f451Sopenharmony_ci break; 3290f66f451Sopenharmony_ci case ICMP_UNREACH_HOST: 3300f66f451Sopenharmony_ci xprintf(" !H"); 3310f66f451Sopenharmony_ci ++fexit; 3320f66f451Sopenharmony_ci break; 3330f66f451Sopenharmony_ci case ICMP_UNREACH_PROTOCOL: 3340f66f451Sopenharmony_ci xprintf(" !P"); 3350f66f451Sopenharmony_ci dest_reach = 1; 3360f66f451Sopenharmony_ci break; 3370f66f451Sopenharmony_ci case ICMP_UNREACH_NEEDFRAG: 3380f66f451Sopenharmony_ci xprintf(" !F-%d", pmtu); 3390f66f451Sopenharmony_ci ++fexit; 3400f66f451Sopenharmony_ci break; 3410f66f451Sopenharmony_ci case ICMP_UNREACH_SRCFAIL: 3420f66f451Sopenharmony_ci xprintf(" !S"); 3430f66f451Sopenharmony_ci ++fexit; 3440f66f451Sopenharmony_ci break; 3450f66f451Sopenharmony_ci case ICMP_UNREACH_FILTER_PROHIB: 3460f66f451Sopenharmony_ci case ICMP_UNREACH_NET_PROHIB: 3470f66f451Sopenharmony_ci xprintf(" !A"); 3480f66f451Sopenharmony_ci ++fexit; 3490f66f451Sopenharmony_ci break; 3500f66f451Sopenharmony_ci case ICMP_UNREACH_HOST_PROHIB: 3510f66f451Sopenharmony_ci xprintf(" !C"); 3520f66f451Sopenharmony_ci ++fexit; 3530f66f451Sopenharmony_ci break; 3540f66f451Sopenharmony_ci case ICMP_UNREACH_HOST_PRECEDENCE: 3550f66f451Sopenharmony_ci xprintf(" !V"); 3560f66f451Sopenharmony_ci ++fexit; 3570f66f451Sopenharmony_ci break; 3580f66f451Sopenharmony_ci case ICMP_UNREACH_PRECEDENCE_CUTOFF: 3590f66f451Sopenharmony_ci xprintf(" !C"); 3600f66f451Sopenharmony_ci ++fexit; 3610f66f451Sopenharmony_ci break; 3620f66f451Sopenharmony_ci case ICMP_UNREACH_NET_UNKNOWN: 3630f66f451Sopenharmony_ci case ICMP_UNREACH_HOST_UNKNOWN: 3640f66f451Sopenharmony_ci xprintf(" !U"); 3650f66f451Sopenharmony_ci ++fexit; 3660f66f451Sopenharmony_ci break; 3670f66f451Sopenharmony_ci case ICMP_UNREACH_ISOLATED: 3680f66f451Sopenharmony_ci xprintf(" !I"); 3690f66f451Sopenharmony_ci ++fexit; 3700f66f451Sopenharmony_ci break; 3710f66f451Sopenharmony_ci case ICMP_UNREACH_TOSNET: 3720f66f451Sopenharmony_ci case ICMP_UNREACH_TOSHOST: 3730f66f451Sopenharmony_ci xprintf(" !T"); 3740f66f451Sopenharmony_ci ++fexit; 3750f66f451Sopenharmony_ci break; 3760f66f451Sopenharmony_ci default: 3770f66f451Sopenharmony_ci break; 3780f66f451Sopenharmony_ci } 3790f66f451Sopenharmony_ci break; 3800f66f451Sopenharmony_ci } else { 3810f66f451Sopenharmony_ci struct icmp6_hdr *ricmp = (struct icmp6_hdr *) toybuf; 3820f66f451Sopenharmony_ci 3830f66f451Sopenharmony_ci if ((ricmp->icmp6_type == ICMP6_TIME_EXCEEDED 3840f66f451Sopenharmony_ci && ricmp->icmp6_code == ICMP6_TIME_EXCEED_TRANSIT) 3850f66f451Sopenharmony_ci || ricmp->icmp6_type == ICMP6_DST_UNREACH 3860f66f451Sopenharmony_ci || ricmp->icmp6_type == ICMP6_ECHO_REPLY) { 3870f66f451Sopenharmony_ci 3880f66f451Sopenharmony_ci struct ip6_hdr *hip; 3890f66f451Sopenharmony_ci struct udphdr *hudp; 3900f66f451Sopenharmony_ci int hdr_next; 3910f66f451Sopenharmony_ci 3920f66f451Sopenharmony_ci hip = (struct ip6_hdr *)(ricmp + 1); 3930f66f451Sopenharmony_ci hudp = (struct udphdr*) (hip + 1); 3940f66f451Sopenharmony_ci hdr_next = hip->ip6_nxt; 3950f66f451Sopenharmony_ci if (hdr_next == IPPROTO_FRAGMENT) { 3960f66f451Sopenharmony_ci hdr_next = *(unsigned char*)hudp; 3970f66f451Sopenharmony_ci hudp++; 3980f66f451Sopenharmony_ci } 3990f66f451Sopenharmony_ci 4000f66f451Sopenharmony_ci if (hdr_next == IPPROTO_UDP) { 4010f66f451Sopenharmony_ci struct payload_s *pkt = (struct payload_s*)(hudp + 1); 4020f66f451Sopenharmony_ci if ((pkt->ident == TT.ident) && (pkt->seq == seq)) 4030f66f451Sopenharmony_ci icmp_res = (ricmp->icmp6_type == ICMP6_TIME_EXCEEDED) ? -1 : 4040f66f451Sopenharmony_ci ricmp->icmp6_code; 4050f66f451Sopenharmony_ci } 4060f66f451Sopenharmony_ci } 4070f66f451Sopenharmony_ci 4080f66f451Sopenharmony_ci if (!icmp_res) continue; 4090f66f451Sopenharmony_ci if (addrlen > 0) { 4100f66f451Sopenharmony_ci if (memcmp(&((struct sockaddr_in6 *)&last_addr)->sin6_addr, 4110f66f451Sopenharmony_ci &((struct sockaddr_in6 *)&from)->sin6_addr, 4120f66f451Sopenharmony_ci sizeof(struct in6_addr))) { 4130f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_n)) { 4140f66f451Sopenharmony_ci char host[NI_MAXHOST]; 4150f66f451Sopenharmony_ci if (!getnameinfo((struct sockaddr *) &from, 4160f66f451Sopenharmony_ci sizeof(from), host, sizeof(host), NULL, 0, 0)) 4170f66f451Sopenharmony_ci xprintf(" %s (", host); 4180f66f451Sopenharmony_ci } 4190f66f451Sopenharmony_ci memset(addr_str, '\0', INET6_ADDRSTRLEN); 4200f66f451Sopenharmony_ci inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr, 4210f66f451Sopenharmony_ci addr_str, INET6_ADDRSTRLEN); 4220f66f451Sopenharmony_ci xprintf(" %s", addr_str); 4230f66f451Sopenharmony_ci 4240f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_n)) xprintf(")"); 4250f66f451Sopenharmony_ci memcpy(&last_addr,&from,sizeof(from)); 4260f66f451Sopenharmony_ci } 4270f66f451Sopenharmony_ci 4280f66f451Sopenharmony_ci if (toys.optflags & FLAG_v) { 4290f66f451Sopenharmony_ci if(print_verbose){ 4300f66f451Sopenharmony_ci memset(addr_str, '\0', INET6_ADDRSTRLEN); 4310f66f451Sopenharmony_ci inet_ntop(AF_INET6, &((struct sockaddr_in6 *) 4320f66f451Sopenharmony_ci &from)->sin6_addr, addr_str, INET6_ADDRSTRLEN); 4330f66f451Sopenharmony_ci rcv_len -= sizeof(struct ip6_hdr); 4340f66f451Sopenharmony_ci xprintf(" %d bytes to %s ", rcv_len, addr_str); 4350f66f451Sopenharmony_ci } 4360f66f451Sopenharmony_ci } 4370f66f451Sopenharmony_ci xprintf(" %u.%03u ms", delta / 1000, delta % 1000); 4380f66f451Sopenharmony_ci delta = 0; 4390f66f451Sopenharmony_ci 4400f66f451Sopenharmony_ci } else xprintf("\t!H"); 4410f66f451Sopenharmony_ci 4420f66f451Sopenharmony_ci switch (icmp_res) { 4430f66f451Sopenharmony_ci case ICMP6_DST_UNREACH_NOPORT: 4440f66f451Sopenharmony_ci ++fexit; 4450f66f451Sopenharmony_ci dest_reach = 1; 4460f66f451Sopenharmony_ci break; 4470f66f451Sopenharmony_ci case ICMP6_DST_UNREACH_NOROUTE: 4480f66f451Sopenharmony_ci xprintf(" !N"); 4490f66f451Sopenharmony_ci ++fexit; 4500f66f451Sopenharmony_ci break; 4510f66f451Sopenharmony_ci case ICMP6_DST_UNREACH_ADDR: 4520f66f451Sopenharmony_ci xprintf(" !H"); 4530f66f451Sopenharmony_ci ++fexit; 4540f66f451Sopenharmony_ci break; 4550f66f451Sopenharmony_ci case ICMP6_DST_UNREACH_ADMIN: 4560f66f451Sopenharmony_ci xprintf(" !S"); 4570f66f451Sopenharmony_ci ++fexit; 4580f66f451Sopenharmony_ci break; 4590f66f451Sopenharmony_ci default: 4600f66f451Sopenharmony_ci break; 4610f66f451Sopenharmony_ci } 4620f66f451Sopenharmony_ci break; 4630f66f451Sopenharmony_ci } 4640f66f451Sopenharmony_ci } //revents 4650f66f451Sopenharmony_ci } 4660f66f451Sopenharmony_ci print_verbose = 0; 4670f66f451Sopenharmony_ci } 4680f66f451Sopenharmony_ci xputc('\n'); 4690f66f451Sopenharmony_ci if(!TT.istraceroute6) { 4700f66f451Sopenharmony_ci if (!memcmp(&((struct sockaddr_in *)&from)->sin_addr, 4710f66f451Sopenharmony_ci &((struct sockaddr_in *)&dest)->sin_addr, sizeof(struct in_addr)) 4720f66f451Sopenharmony_ci || dest_reach || (fexit && fexit >= TT.ttl_probes -1)) 4730f66f451Sopenharmony_ci break; 4740f66f451Sopenharmony_ci } else if (dest_reach || (fexit > 0 && fexit >= TT.ttl_probes -1)) break; 4750f66f451Sopenharmony_ci } 4760f66f451Sopenharmony_ci} 4770f66f451Sopenharmony_ci 4780f66f451Sopenharmony_civoid traceroute_main(void) 4790f66f451Sopenharmony_ci{ 4800f66f451Sopenharmony_ci unsigned pack_size = 0, tyser = 0; 4810f66f451Sopenharmony_ci int lsrr = 0, set = 1; 4820f66f451Sopenharmony_ci 4830f66f451Sopenharmony_ci if(!(toys.optflags & FLAG_4) && 4840f66f451Sopenharmony_ci (inet_pton(AF_INET6, toys.optargs[0], &dest))) 4850f66f451Sopenharmony_ci toys.optflags |= FLAG_6; 4860f66f451Sopenharmony_ci 4870f66f451Sopenharmony_ci memset(&dest, 0, sizeof(dest)); 4880f66f451Sopenharmony_ci if (toys.optflags & FLAG_6) TT.istraceroute6 = 1; 4890f66f451Sopenharmony_ci else TT.istraceroute6 = toys.which->name[10] == '6'; 4900f66f451Sopenharmony_ci 4910f66f451Sopenharmony_ci if(!TT.istraceroute6 && (toys.optflags & FLAG_g)) { 4920f66f451Sopenharmony_ci struct arg_list *node; 4930f66f451Sopenharmony_ci 4940f66f451Sopenharmony_ci for (node = TT.loose_source; node; node = node->next, lsrr++) { 4950f66f451Sopenharmony_ci struct sockaddr_in sin; 4960f66f451Sopenharmony_ci 4970f66f451Sopenharmony_ci memset( &sin, 0, sizeof(sin)); 4980f66f451Sopenharmony_ci if (lsrr >= 8) error_exit("no more than 8 gateways"); // NGATEWAYS 4990f66f451Sopenharmony_ci resolve_addr(node->arg, AF_INET, SOCK_STREAM, 0, &sin); 5000f66f451Sopenharmony_ci TT.gw_list[lsrr] = sin.sin_addr.s_addr; 5010f66f451Sopenharmony_ci } 5020f66f451Sopenharmony_ci } else TT.first_ttl = 1; 5030f66f451Sopenharmony_ci 5040f66f451Sopenharmony_ci TT.msg_len = pack_size = ICMP_HD_SIZE4; //udp payload is also 8bytes 5050f66f451Sopenharmony_ci if (toys.optargs[1]) 5060f66f451Sopenharmony_ci TT.msg_len = atolx_range(toys.optargs[1], pack_size, 32768);//max packet size 5070f66f451Sopenharmony_ci 5080f66f451Sopenharmony_ci TT.recv_sock = xsocket((TT.istraceroute6 ? AF_INET6 : AF_INET), SOCK_RAW, 5090f66f451Sopenharmony_ci (TT.istraceroute6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP)); 5100f66f451Sopenharmony_ci 5110f66f451Sopenharmony_ci if (TT.istraceroute6) { 5120f66f451Sopenharmony_ci int two = 2; 5130f66f451Sopenharmony_ci#ifdef IPV6_RECVPKTINFO 5140f66f451Sopenharmony_ci setsockopt(TT.recv_sock, SOL_IPV6, IPV6_RECVPKTINFO, &set, 5150f66f451Sopenharmony_ci sizeof(set)); 5160f66f451Sopenharmony_ci setsockopt(TT.recv_sock, SOL_IPV6, IPV6_2292PKTINFO, &set, 5170f66f451Sopenharmony_ci sizeof(set)); 5180f66f451Sopenharmony_ci#else 5190f66f451Sopenharmony_ci setsockopt(TT.recv_sock, SOL_IPV6, IPV6_PKTINFO, &set, sizeof(set)); 5200f66f451Sopenharmony_ci#endif 5210f66f451Sopenharmony_ci 5220f66f451Sopenharmony_ci if (setsockopt(TT.recv_sock, SOL_RAW, IPV6_CHECKSUM, &two, 5230f66f451Sopenharmony_ci sizeof(two)) < 0) perror_exit("setsockopt RAW_CHECKSUM"); 5240f66f451Sopenharmony_ci } 5250f66f451Sopenharmony_ci 5260f66f451Sopenharmony_ci set_flag_dr(TT.recv_sock); 5270f66f451Sopenharmony_ci 5280f66f451Sopenharmony_ci if (!TT.istraceroute6) { 5290f66f451Sopenharmony_ci if (toys.optflags & FLAG_U) 5300f66f451Sopenharmony_ci TT.snd_sock = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 5310f66f451Sopenharmony_ci else TT.snd_sock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 5320f66f451Sopenharmony_ci 5330f66f451Sopenharmony_ci if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock); 5340f66f451Sopenharmony_ci 5350f66f451Sopenharmony_ci resolve_addr(toys.optargs[0], AF_INET, ((toys.optflags & FLAG_U) ? 5360f66f451Sopenharmony_ci SOCK_DGRAM : SOCK_RAW), ((toys.optflags & FLAG_U) ? IPPROTO_UDP : 5370f66f451Sopenharmony_ci IPPROTO_ICMP), &dest); 5380f66f451Sopenharmony_ci if (lsrr > 0) { 5390f66f451Sopenharmony_ci unsigned char optlist[MAX_IPOPTLEN]; 5400f66f451Sopenharmony_ci unsigned size; 5410f66f451Sopenharmony_ci 5420f66f451Sopenharmony_ci TT.gw_list[lsrr] = ((struct sockaddr_in *)&dest)->sin_addr.s_addr; 5430f66f451Sopenharmony_ci ++lsrr; 5440f66f451Sopenharmony_ci 5450f66f451Sopenharmony_ci optlist[0] = IPOPT_NOP; 5460f66f451Sopenharmony_ci optlist[1] = IPOPT_LSRR;// loose source route option 5470f66f451Sopenharmony_ci size = lsrr * sizeof(TT.gw_list[0]); 5480f66f451Sopenharmony_ci optlist[2] = size + 3; 5490f66f451Sopenharmony_ci optlist[3] = IPOPT_MINOFF; 5500f66f451Sopenharmony_ci memcpy(optlist + 4, TT.gw_list, size); 5510f66f451Sopenharmony_ci 5520f66f451Sopenharmony_ci if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_OPTIONS, 5530f66f451Sopenharmony_ci (char *)optlist, size + sizeof(TT.gw_list[0])) < 0) 5540f66f451Sopenharmony_ci perror_exit("LSRR IP_OPTIONS"); 5550f66f451Sopenharmony_ci } 5560f66f451Sopenharmony_ci } else TT.snd_sock = xsocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 5570f66f451Sopenharmony_ci 5580f66f451Sopenharmony_ci if (setsockopt(TT.snd_sock, SOL_SOCKET, SO_SNDBUF, &TT.msg_len, 5590f66f451Sopenharmony_ci sizeof(TT.msg_len)) < 0) perror_exit("SO_SNDBUF failed "); 5600f66f451Sopenharmony_ci 5610f66f451Sopenharmony_ci if (!TT.istraceroute6) { 5620f66f451Sopenharmony_ci if ((toys.optflags & FLAG_t) && 5630f66f451Sopenharmony_ci setsockopt(TT.snd_sock, IPPROTO_IP, IP_TOS, &tyser, sizeof(tyser)) < 0) 5640f66f451Sopenharmony_ci perror_exit("IP_TOS %ld failed ", TT.tos); 5650f66f451Sopenharmony_ci 5660f66f451Sopenharmony_ci#ifdef IP_DONTFRAG 5670f66f451Sopenharmony_ci if ((toys.optflags & FLAG_F) && 5680f66f451Sopenharmony_ci (setsockopt(TT.snd_sock, IPPROTO_IP, IP_DONTFRAG, &set, 5690f66f451Sopenharmony_ci sizeof(set)) < 0)) perror_exit("IP_DONTFRAG failed "); 5700f66f451Sopenharmony_ci#endif 5710f66f451Sopenharmony_ci } else if (setsockopt(TT.snd_sock, IPPROTO_IPV6, IPV6_TCLASS, &TT.tos, 5720f66f451Sopenharmony_ci sizeof(TT.tos)) < 0) perror_exit("IPV6_TCLASS %ld failed ", TT.tos); 5730f66f451Sopenharmony_ci 5740f66f451Sopenharmony_ci set_flag_dr(TT.snd_sock); 5750f66f451Sopenharmony_ci TT.packet = xzalloc(TT.msg_len); 5760f66f451Sopenharmony_ci TT.ident = getpid(); 5770f66f451Sopenharmony_ci 5780f66f451Sopenharmony_ci if (!TT.istraceroute6) { 5790f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_U)) TT.ident |= 0x8000; 5800f66f451Sopenharmony_ci if (toys.optflags & FLAG_s) { 5810f66f451Sopenharmony_ci struct sockaddr_in source; 5820f66f451Sopenharmony_ci 5830f66f451Sopenharmony_ci memset(&source, 0, sizeof(source)); 5840f66f451Sopenharmony_ci if (!inet_aton(TT.src_ip, &(source.sin_addr))) 5850f66f451Sopenharmony_ci error_exit("bad address: %s", TT.src_ip); 5860f66f451Sopenharmony_ci if (setsockopt(TT.snd_sock, IPPROTO_IP, IP_MULTICAST_IF, 5870f66f451Sopenharmony_ci (struct sockaddr*)&source, sizeof(struct sockaddr_in))) 5880f66f451Sopenharmony_ci perror_exit("can't set multicast source interface"); 5890f66f451Sopenharmony_ci xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in)); 5900f66f451Sopenharmony_ci } 5910f66f451Sopenharmony_ci 5920f66f451Sopenharmony_ci if(TT.first_ttl > TT.max_ttl) 5930f66f451Sopenharmony_ci error_exit("ERROR :Range for -f is 1 to %ld (max ttl)", TT.max_ttl); 5940f66f451Sopenharmony_ci 5950f66f451Sopenharmony_ci xprintf("traceroute to %s(%s)", toys.optargs[0], 5960f66f451Sopenharmony_ci inet_ntoa(((struct sockaddr_in *)&dest)->sin_addr)); 5970f66f451Sopenharmony_ci } else { 5980f66f451Sopenharmony_ci if (toys.optflags & FLAG_i) bind_to_interface(TT.snd_sock); 5990f66f451Sopenharmony_ci 6000f66f451Sopenharmony_ci resolve_addr(toys.optargs[0], AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &dest); 6010f66f451Sopenharmony_ci if (toys.optflags & FLAG_s) { 6020f66f451Sopenharmony_ci struct sockaddr_in6 source; 6030f66f451Sopenharmony_ci 6040f66f451Sopenharmony_ci memset(&source, 0, sizeof(source)); 6050f66f451Sopenharmony_ci if(inet_pton(AF_INET6, TT.src_ip, &(source.sin6_addr)) <= 0) 6060f66f451Sopenharmony_ci error_exit("bad address: %s", TT.src_ip); 6070f66f451Sopenharmony_ci 6080f66f451Sopenharmony_ci xbind(TT.snd_sock,(struct sockaddr*)&source, sizeof(struct sockaddr_in6)); 6090f66f451Sopenharmony_ci } else { 6100f66f451Sopenharmony_ci struct sockaddr_in6 prb; 6110f66f451Sopenharmony_ci socklen_t len = sizeof(prb); 6120f66f451Sopenharmony_ci int p_fd = xsocket(AF_INET6, SOCK_DGRAM, 0); 6130f66f451Sopenharmony_ci if (toys.optflags & FLAG_i) bind_to_interface(p_fd); 6140f66f451Sopenharmony_ci 6150f66f451Sopenharmony_ci ((struct sockaddr_in6 *)&dest)->sin6_port = htons(1025); 6160f66f451Sopenharmony_ci xconnect(p_fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_in6)); 6170f66f451Sopenharmony_ci if(getsockname(p_fd, (struct sockaddr *)&prb, &len)) 6180f66f451Sopenharmony_ci error_exit("probe addr failed"); 6190f66f451Sopenharmony_ci close(p_fd); 6200f66f451Sopenharmony_ci prb.sin6_port = 0; 6210f66f451Sopenharmony_ci xbind(TT.snd_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6)); 6220f66f451Sopenharmony_ci xbind(TT.recv_sock, (struct sockaddr*)&prb, sizeof(struct sockaddr_in6)); 6230f66f451Sopenharmony_ci } 6240f66f451Sopenharmony_ci 6250f66f451Sopenharmony_ci inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&dest)->sin6_addr, 6260f66f451Sopenharmony_ci addr_str, INET6_ADDRSTRLEN); 6270f66f451Sopenharmony_ci xprintf("traceroute6 to %s(%s)", toys.optargs[0], addr_str); 6280f66f451Sopenharmony_ci } 6290f66f451Sopenharmony_ci 6300f66f451Sopenharmony_ci if (toys.optflags & FLAG_s) xprintf(" from %s",TT.src_ip); 6310f66f451Sopenharmony_ci xprintf(", %ld hops max, %u byte packets\n", TT.max_ttl, TT.msg_len); 6320f66f451Sopenharmony_ci 6330f66f451Sopenharmony_ci do_trace(); 6340f66f451Sopenharmony_ci} 635