#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/stropts.h>
#include <sys/file.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include <netdb.h>
#include <stdlib.h>
#include <libinetutil.h>
#include "ping.h"
struct ip_sourceroute {
uint8_t ipsr_code;
uint8_t ipsr_len;
uint8_t ipsr_ptr;
uint8_t ipsr_addrs[1][sizeof (struct in_addr)];
};
static void pr_options(uchar_t *, int);
static void pr_rropt(uchar_t *, int, boolean_t);
static void pr_tsopt(uchar_t *, int);
static char *pr_type(int);
void
set_IPv4_options(int sock, union any_in_addr *gw_IP_list, int gw_count,
struct in_addr *src, struct in_addr *dst)
{
int req_size;
char srr[ROUTE_SIZE + 1];
char *bufp;
int optsize = ROUTE_SIZE;
struct ip_sourceroute *srp;
struct ip_timestamp *tsp;
int i;
if (rr_option || ts_option || gw_count > 0) {
bzero(srr, sizeof (srr));
bufp = srr;
if (gw_count > 0) {
req_size = 3 + (sizeof (struct in_addr)) * gw_count;
if (optsize < req_size) {
Fprintf(stderr, "%s: too many IPv4 gateways\n",
progname);
exit(EXIT_FAILURE);
}
srp = (struct ip_sourceroute *)bufp;
srp->ipsr_code = strict ? IPOPT_SSRR : IPOPT_LSRR;
srp->ipsr_len = req_size;
srp->ipsr_ptr = IPOPT_MINOFF;
for (i = 0; i < gw_count; i++) {
bcopy((char *)&gw_IP_list[i].addr,
&srp->ipsr_addrs[i],
sizeof (struct in_addr));
}
optsize -= srp->ipsr_len;
bufp += srp->ipsr_len;
}
if (ts_option) {
if (optsize < IPOPT_MINOFF) {
Fprintf(stderr,
"%s: no room for timestamp option\n",
progname);
exit(EXIT_FAILURE);
}
tsp = (struct ip_timestamp *)bufp;
tsp->ipt_code = IPOPT_TS;
tsp->ipt_len = optsize;
tsp->ipt_ptr = IPOPT_MINOFF + 1;
tsp->ipt_flg = ts_flag & 0x0f;
if (tsp->ipt_flg > IPOPT_TS_TSANDADDR) {
req_size = IPOPT_MINOFF +
2 * sizeof (struct ipt_ta);
req_size++;
if (optsize < req_size) {
Fprintf(stderr, "%s: no room for "
"timestamp option\n", progname);
exit(EXIT_FAILURE);
}
bcopy((char *)dst,
&tsp->ipt_timestamp.ipt_ta[0].ipt_addr,
sizeof (struct in_addr));
bcopy((char *)src,
&tsp->ipt_timestamp.ipt_ta[1].ipt_addr,
sizeof (struct in_addr));
tsp->ipt_len = req_size;
}
optsize -= tsp->ipt_len;
bufp += tsp->ipt_len;
}
if (rr_option) {
if (optsize < IPOPT_MINOFF) {
Fprintf(stderr,
"%s: no room for record route option\n",
progname);
exit(EXIT_FAILURE);
}
srp = (struct ip_sourceroute *)bufp;
srp->ipsr_code = IPOPT_RR;
srp->ipsr_len = optsize;
srp->ipsr_ptr = IPOPT_MINOFF;
optsize -= srp->ipsr_len;
bufp += srp->ipsr_len;
}
optsize = bufp - srr;
if (optsize & 0x3)
optsize = (optsize & ~0x3) + 4;
if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, srr, optsize) <
0) {
Fprintf(stderr, "%s: setsockopt IP_OPTIONS %s\n",
progname, strerror(errno));
exit(EXIT_FAILURE);
}
}
}
void
check_reply(struct addrinfo *ai_dst, struct msghdr *msg, int cc,
ushort_t udp_src_port)
{
struct ip *ip;
struct icmp *icp;
struct udphdr *up;
union any_in_addr dst_addr;
uchar_t *buf;
int32_t *intp;
struct sockaddr_in *from;
struct timeval *tp;
struct timeval tv;
int hlen, hlen1;
int64_t triptime;
boolean_t valid_reply = _B_FALSE;
boolean_t reply_matched_current_target = _B_FALSE;
boolean_t last_reply_from_targetaddr = _B_FALSE;
int cc_left;
char tmp_buf[INET6_ADDRSTRLEN];
static char *unreach[] = {
"Net Unreachable",
"Host Unreachable",
"Protocol Unreachable",
"Port Unreachable",
"Fragmentation needed and DF set",
"Source Route Failed",
"Net Unknown",
"Host Unknown",
"Source Host Isolated",
"Dest Net Prohibited",
"Dest Host Prohibited",
"Net Unreachable for TOS",
"Host Unreachable for TOS",
"Communication Administratively Prohibited",
"Host Precedence Violation",
"Precedence Cutoff in Effect"
};
static char *redirect[] = {
"Net",
"Host",
"TOS Net",
"TOS Host"
};
static char *timexceed[] = {
"Time exceeded in transit",
"Time exceeded during reassembly"
};
boolean_t print_newline = _B_FALSE;
int i;
buf = (uchar_t *)msg->msg_iov->iov_base;
from = (struct sockaddr_in *)msg->msg_name;
intp = (int32_t *)buf;
ping_gettime(msg, &tv);
ip = (struct ip *)buf;
hlen = ip->ip_hl << 2;
if ((cc < sizeof (struct ip)) || (cc < hlen + ICMP_MINLEN)) {
if (verbose) {
Printf("packet too short (%d bytes) from %s\n", cc,
pr_name4(from));
}
return;
}
cc -= hlen;
icp = (struct icmp *)(buf + hlen);
if (ip->ip_p == 0) {
icp = (struct icmp *)buf;
}
cc_left = cc - ICMP_MINLEN;
switch (icp->icmp_type) {
case ICMP_UNREACH:
ip = &icp->icmp_ip;
hlen1 = ip->ip_hl << 2;
if ((cc_left < sizeof (struct ip)) ||
(cc_left < hlen1 + sizeof (struct udphdr))) {
if (verbose) {
Printf("packet too short (%d bytes) from %s\n",
cc, pr_name4(from));
}
return;
}
cc_left -= hlen1 + sizeof (struct udphdr);
up = (struct udphdr *)((uchar_t *)ip + hlen1);
if (icp->icmp_code == ICMP_UNREACH_PORT &&
ip->ip_p == IPPROTO_UDP &&
udp_src_port == up->uh_sport &&
use_udp) {
valid_reply = _B_TRUE;
} else {
valid_reply = _B_FALSE;
}
if (valid_reply) {
(void) sighold(SIGALRM);
is_alive = _B_TRUE;
nreceived++;
reply_matched_current_target =
seq_match(current_targetaddr->starting_seq_num,
current_targetaddr->num_sent,
ntohs(up->uh_dport));
if (reply_matched_current_target) {
current_targetaddr->got_reply = _B_TRUE;
nreceived_last_target++;
if (stats && probe_all && npackets > 0 &&
((current_targetaddr->starting_seq_num +
current_targetaddr->num_probes - 1) %
(MAX_PORT + 1) == ntohs(up->uh_dport)) &&
(current_targetaddr->num_probes ==
current_targetaddr->num_sent))
last_reply_from_targetaddr = _B_TRUE;
} else {
if (probe_all && !stats) {
valid_reply = _B_FALSE;
if (!verbose) {
(void) sigrelse(SIGALRM);
return;
}
}
}
}
if (valid_reply && !stats) {
if (reply_matched_current_target) {
(void) alarm(0);
(void) sigset(SIGALRM, SIG_IGN);
current_targetaddr->probing_done = _B_TRUE;
}
(void) sigrelse(SIGALRM);
if (!probe_all) {
Printf("%s is alive\n", targethost);
} else {
(void) inet_ntop(AF_INET, (void *)&ip->ip_dst,
tmp_buf, sizeof (tmp_buf));
if (nflag) {
Printf("%s is alive\n", tmp_buf);
} else {
Printf("%s (%s) is alive\n",
targethost, tmp_buf);
}
}
if (reply_matched_current_target) {
send_scheduled_probe();
(void) sigset(SIGALRM, sigalrm_handler);
schedule_sigalrm();
}
return;
} else {
if (!last_reply_from_targetaddr)
(void) sigrelse(SIGALRM);
}
dst_addr.addr = ip->ip_dst;
if (valid_reply) {
Printf("%d bytes from %s: ", cc, pr_name4(from));
Printf("udp_port=%d. ", ntohs(up->uh_dport));
print_newline = _B_TRUE;
} else if (is_a_target(ai_dst, &dst_addr) || verbose) {
if (icp->icmp_code >= A_CNT(unreach)) {
Printf("ICMP %d Unreachable from gateway %s\n",
icp->icmp_code, pr_name4(from));
} else {
Printf("ICMP %s from gateway %s\n",
unreach[icp->icmp_code], pr_name4(from));
}
Printf(" for %s from %s", pr_protocol(ip->ip_p),
pr_name((char *)&ip->ip_src, AF_INET));
Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
if (ip->ip_p == IPPROTO_TCP ||
ip->ip_p == IPPROTO_UDP) {
Printf(" port %d ", ntohs(up->uh_dport));
}
print_newline = _B_TRUE;
}
if (valid_reply && datalen >= sizeof (struct timeval) &&
cc_left >= sizeof (struct timeval)) {
tp = (struct timeval *)((char *)up +
sizeof (struct udphdr));
(void) tvsub(&tv, tp);
triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
tsum += triptime;
tsum2 += triptime*triptime;
if (triptime < tmin)
tmin = triptime;
if (triptime > tmax)
tmax = triptime;
print_newline = _B_TRUE;
}
if (print_newline)
(void) putchar('\n');
if (last_reply_from_targetaddr) {
(void) alarm(0);
current_targetaddr->probing_done = _B_TRUE;
(void) sigrelse(SIGALRM);
send_scheduled_probe();
schedule_sigalrm();
}
break;
case ICMP_REDIRECT:
if (cc_left < sizeof (struct ip)) {
if (verbose) {
Printf("packet too short (%d bytes) from %s\n",
cc, pr_name4(from));
}
return;
}
ip = &icp->icmp_ip;
dst_addr.addr = ip->ip_dst;
if (is_a_target(ai_dst, &dst_addr) || verbose) {
if (icp->icmp_code >= A_CNT(redirect)) {
Printf("ICMP %d redirect from gateway %s\n",
icp->icmp_code, pr_name4(from));
} else {
Printf("ICMP %s redirect from gateway %s\n",
redirect[icp->icmp_code], pr_name4(from));
}
Printf(" to %s",
pr_name((char *)&icp->icmp_gwaddr, AF_INET));
Printf(" for %s\n",
pr_name((char *)&ip->ip_dst, AF_INET));
}
break;
case ICMP_ECHOREPLY:
if (ntohs(icp->icmp_id) == ident) {
if (!use_udp && !use_icmp_ts)
valid_reply = _B_TRUE;
else
valid_reply = _B_FALSE;
} else {
return;
}
if (valid_reply) {
(void) sighold(SIGALRM);
is_alive = _B_TRUE;
nreceived++;
reply_matched_current_target =
seq_match(current_targetaddr->starting_seq_num,
current_targetaddr->num_sent,
ntohs(icp->icmp_seq));
if (reply_matched_current_target) {
current_targetaddr->got_reply = _B_TRUE;
nreceived_last_target++;
if (stats && probe_all && npackets > 0 &&
((current_targetaddr->starting_seq_num +
current_targetaddr->num_probes - 1) %
(MAX_ICMP_SEQ + 1) ==
ntohs(icp->icmp_seq)) &&
(current_targetaddr->num_probes ==
current_targetaddr->num_sent))
last_reply_from_targetaddr = _B_TRUE;
} else {
if (probe_all && !stats) {
valid_reply = _B_FALSE;
if (!verbose) {
(void) sigrelse(SIGALRM);
return;
}
}
}
}
if (!stats && valid_reply) {
if (reply_matched_current_target) {
(void) alarm(0);
(void) sigset(SIGALRM, SIG_IGN);
current_targetaddr->probing_done = _B_TRUE;
}
(void) sigrelse(SIGALRM);
if (!probe_all) {
Printf("%s is alive\n", targethost);
} else {
if (send_reply) {
(void) find_dstaddr(
ntohs(icp->icmp_seq), &dst_addr);
(void) inet_ntop(AF_INET,
(void *)&dst_addr.addr,
tmp_buf, sizeof (tmp_buf));
} else {
(void) inet_ntop(AF_INET,
(void *)&from->sin_addr,
tmp_buf, sizeof (tmp_buf));
}
if (nflag) {
Printf("%s is alive\n", tmp_buf);
} else {
Printf("%s (%s) is alive\n",
targethost, tmp_buf);
}
}
if (reply_matched_current_target) {
send_scheduled_probe();
(void) sigset(SIGALRM, sigalrm_handler);
schedule_sigalrm();
}
return;
} else {
if (!last_reply_from_targetaddr)
(void) sigrelse(SIGALRM);
}
if (send_reply) {
(void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr);
Printf("%d bytes from %s: ", cc,
pr_name((char *)&dst_addr.addr, AF_INET));
} else {
Printf("%d bytes from %s: ", cc, pr_name4(from));
}
Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq));
if (valid_reply && datalen >= sizeof (struct timeval) &&
cc_left >= sizeof (struct timeval)) {
tp = (struct timeval *)&icp->icmp_data[0];
(void) tvsub(&tv, tp);
triptime = (int64_t)tv.tv_sec * MICROSEC + tv.tv_usec;
Printf("time=" TIMEFORMAT " ms", triptime/1000.0);
tsum += triptime;
tsum2 += triptime*triptime;
if (triptime < tmin)
tmin = triptime;
if (triptime > tmax)
tmax = triptime;
}
(void) putchar('\n');
if (last_reply_from_targetaddr) {
(void) alarm(0);
current_targetaddr->probing_done = _B_TRUE;
(void) sigrelse(SIGALRM);
send_scheduled_probe();
schedule_sigalrm();
}
break;
case ICMP_SOURCEQUENCH:
if (cc_left < sizeof (struct ip)) {
if (verbose) {
Printf("packet too short (%d bytes) from %s\n",
cc, pr_name4(from));
}
return;
}
ip = &icp->icmp_ip;
hlen1 = ip->ip_hl << 2;
dst_addr.addr = ip->ip_dst;
if (is_a_target(ai_dst, &dst_addr) || verbose) {
Printf("ICMP Source Quench from %s\n", pr_name4(from));
Printf(" for %s from %s", pr_protocol(ip->ip_p),
pr_name((char *)&ip->ip_src, AF_INET));
Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
if ((ip->ip_p == IPPROTO_TCP ||
ip->ip_p == IPPROTO_UDP) &&
(cc_left >= hlen1 + 4)) {
up = (struct udphdr *)((uchar_t *)ip + hlen1);
Printf(" port %d", ntohs(up->uh_dport));
}
(void) putchar('\n');
}
break;
case ICMP_PARAMPROB:
if (cc_left < sizeof (struct ip)) {
if (verbose) {
Printf("packet too short (%d bytes) from %s\n",
cc, pr_name4(from));
}
return;
}
ip = &icp->icmp_ip;
hlen1 = ip->ip_hl << 2;
dst_addr.addr = ip->ip_dst;
if (is_a_target(ai_dst, &dst_addr) || verbose) {
switch (icp->icmp_code) {
case ICMP_PARAMPROB_OPTABSENT:
Printf("ICMP Missing a Required Option "
"parameter problem from %s\n",
pr_name4(from));
Printf(" option type = %d", icp->icmp_pptr);
break;
case ICMP_PARAMPROB_BADLENGTH:
Printf("ICMP Bad Length parameter problem "
"from %s\n", pr_name4(from));
Printf(" in byte %d", icp->icmp_pptr);
if (icp->icmp_pptr <= hlen1) {
Printf(" (value 0x%x)",
*((char *)ip + icp->icmp_pptr));
}
break;
case 0:
default:
Printf("ICMP Parameter Problem from %s\n",
pr_name4(from));
Printf(" in byte %d", icp->icmp_pptr);
if (icp->icmp_pptr <= hlen1) {
Printf(" (value 0x%x)",
*((char *)ip + icp->icmp_pptr));
}
break;
}
Printf(" for %s from %s", pr_protocol(ip->ip_p),
pr_name((char *)&ip->ip_src, AF_INET));
Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
if ((ip->ip_p == IPPROTO_TCP ||
ip->ip_p == IPPROTO_UDP) &&
(cc_left >= hlen1 + 4)) {
up = (struct udphdr *)((uchar_t *)ip + hlen1);
Printf(" port %d", ntohs(up->uh_dport));
}
(void) putchar('\n');
}
break;
case ICMP_TIMXCEED:
if (cc_left < sizeof (struct ip)) {
if (verbose) {
Printf("packet too short (%d bytes) from %s\n",
cc, pr_name4(from));
}
return;
}
ip = &icp->icmp_ip;
hlen1 = ip->ip_hl << 2;
dst_addr.addr = ip->ip_dst;
if (is_a_target(ai_dst, &dst_addr) || verbose) {
if (icp->icmp_code >= A_CNT(timexceed)) {
Printf("ICMP %d time exceeded from %s\n",
icp->icmp_code, pr_name4(from));
} else {
Printf("ICMP %s from %s\n",
timexceed[icp->icmp_code],
pr_name4(from));
}
Printf(" for %s from %s", pr_protocol(ip->ip_p),
pr_name((char *)&ip->ip_src, AF_INET));
Printf(" to %s", pr_name((char *)&ip->ip_dst, AF_INET));
if ((ip->ip_p == IPPROTO_TCP ||
ip->ip_p == IPPROTO_UDP) &&
(cc_left >= hlen1 + 4)) {
up = (struct udphdr *)((uchar_t *)ip + hlen1);
Printf(" port %d", ntohs(up->uh_dport));
}
(void) putchar('\n');
}
break;
case ICMP_TSTAMPREPLY:
if (cc_left < sizeof (struct id_ts)) {
if (verbose) {
Printf("packet too short (%d bytes) from %s\n",
cc, pr_name4(from));
}
return;
}
if (ntohs(icp->icmp_id) == ident) {
if (use_icmp_ts)
valid_reply = _B_TRUE;
else
valid_reply = _B_FALSE;
} else {
return;
}
if (valid_reply) {
(void) sighold(SIGALRM);
is_alive = _B_TRUE;
nreceived++;
reply_matched_current_target =
seq_match(current_targetaddr->starting_seq_num,
current_targetaddr->num_sent,
ntohs(icp->icmp_seq));
if (reply_matched_current_target) {
current_targetaddr->got_reply = _B_TRUE;
nreceived_last_target++;
if (stats && probe_all && npackets > 0 &&
((current_targetaddr->starting_seq_num +
current_targetaddr->num_probes - 1) %
(MAX_ICMP_SEQ + 1) ==
ntohs(icp->icmp_seq)) &&
(current_targetaddr->num_probes ==
current_targetaddr->num_sent))
last_reply_from_targetaddr = _B_TRUE;
} else {
if (probe_all && !stats) {
valid_reply = _B_FALSE;
if (!verbose) {
(void) sigrelse(SIGALRM);
return;
}
}
}
}
if (!stats && valid_reply) {
if (reply_matched_current_target) {
(void) alarm(0);
(void) sigset(SIGALRM, SIG_IGN);
current_targetaddr->probing_done = _B_TRUE;
}
(void) sigrelse(SIGALRM);
if (!probe_all) {
Printf("%s is alive\n", targethost);
} else {
if (send_reply) {
(void) find_dstaddr(
ntohs(icp->icmp_seq), &dst_addr);
(void) inet_ntop(AF_INET,
(void *)&dst_addr.addr,
tmp_buf, sizeof (tmp_buf));
} else {
(void) inet_ntop(AF_INET,
(void *)&from->sin_addr,
tmp_buf, sizeof (tmp_buf));
}
if (nflag) {
Printf("%s is alive\n", tmp_buf);
} else {
Printf("%s (%s) is alive\n",
targethost, tmp_buf);
}
}
if (reply_matched_current_target) {
send_scheduled_probe();
(void) sigset(SIGALRM, sigalrm_handler);
schedule_sigalrm();
}
return;
} else {
if (!last_reply_from_targetaddr)
(void) sigrelse(SIGALRM);
}
if (send_reply) {
(void) find_dstaddr(ntohs(icp->icmp_seq), &dst_addr);
Printf("%d bytes from %s: ", cc,
pr_name((char *)&dst_addr.addr, AF_INET));
} else {
Printf("%d bytes from %s: ", cc, pr_name4(from));
}
Printf("icmp_seq=%d. ", ntohs(icp->icmp_seq));
Printf("orig = %lu, recv = %lu, xmit = %lu ",
(ulong_t)ntohl(icp->icmp_otime),
(ulong_t)ntohl(icp->icmp_rtime),
(ulong_t)ntohl(icp->icmp_ttime));
if (valid_reply) {
triptime = (tv.tv_sec % (24LL * 60 * 60)) * MILLISEC +
(tv.tv_usec / (MICROSEC/MILLISEC));
triptime -= ntohl(icp->icmp_otime);
if (triptime < 0)
triptime += 24LL * 60 * 60 * MILLISEC;
Printf("time=%d. ms", (int)triptime);
triptime *= (MICROSEC/MILLISEC);
tsum += triptime;
tsum2 += triptime*triptime;
if (triptime < tmin)
tmin = triptime;
if (triptime > tmax)
tmax = triptime;
}
(void) putchar('\n');
if (last_reply_from_targetaddr) {
(void) alarm(0);
current_targetaddr->probing_done = _B_TRUE;
(void) sigrelse(SIGALRM);
send_scheduled_probe();
schedule_sigalrm();
}
break;
case ICMP_ROUTERADVERT:
case ICMP_ROUTERSOLICIT:
return;
case ICMP_ECHO:
case ICMP_TSTAMP:
case ICMP_IREQ:
case ICMP_MASKREQ:
return;
case ICMP_IREQREPLY:
case ICMP_MASKREPLY:
return;
default:
if (verbose) {
Printf("%d bytes from %s:\n", cc, pr_name4(from));
Printf("icmp_type=%d (%s) ",
icp->icmp_type, pr_type(icp->icmp_type));
Printf("icmp_code=%d\n", icp->icmp_code);
for (i = 0; i < 12; i++) {
Printf("x%2.2x: x%8.8x\n",
i * sizeof (int32_t), *intp++);
}
}
break;
}
buf += sizeof (struct ip);
hlen -= sizeof (struct ip);
if (verbose && hlen > 0)
pr_options((uchar_t *)buf, hlen);
}
static void
pr_options(uchar_t *opt, int optlength)
{
int curlength;
Printf(" IP options: ");
while (optlength > 0) {
curlength = opt[1];
switch (*opt) {
case IPOPT_EOL:
optlength = 0;
break;
case IPOPT_NOP:
opt++;
optlength--;
continue;
case IPOPT_RR:
Printf(" <record route> ");
pr_rropt(opt, curlength, _B_TRUE);
break;
case IPOPT_TS:
Printf(" <time stamp> ");
pr_tsopt(opt, curlength);
break;
case IPOPT_SECURITY:
Printf(" <security>");
break;
case IPOPT_LSRR:
Printf(" <loose source route> ");
pr_rropt(opt, curlength, _B_FALSE);
break;
case IPOPT_SATID:
Printf(" <stream id>");
break;
case IPOPT_SSRR:
Printf(" <strict source route> ");
pr_rropt(opt, curlength, _B_FALSE);
break;
default:
Printf(" <option %d, len %d>", *opt, curlength);
break;
}
opt += curlength;
optlength -= curlength;
}
(void) putchar('\n');
}
static void
pr_rropt(uchar_t *opt, int length, boolean_t rrflag)
{
struct ip_sourceroute *rrp;
int sr_index = 0;
struct in_addr addr;
rrp = (struct ip_sourceroute *)opt;
length -= 3;
while (length > 0) {
if ((rrp->ipsr_ptr == (sr_index + 1) * sizeof (addr)) &&
rrflag) {
Printf(" (End of record)");
break;
}
bcopy(&rrp->ipsr_addrs[sr_index], &addr, sizeof (addr));
Printf("%s", pr_name((char *)&addr, AF_INET));
if (rrp->ipsr_ptr == (sr_index + 1) * sizeof (addr)) {
Printf("(Current)");
}
sr_index++;
length -= sizeof (addr);
if (length > 0)
Printf(", ");
}
}
static void
pr_tsopt(uchar_t *opt, int length)
{
boolean_t address_present;
boolean_t rrflag;
struct ip_timestamp *tsp;
int ts_index = 0;
struct in_addr addr;
size_t data_len;
int32_t time;
tsp = (struct ip_timestamp *)opt;
switch (tsp->ipt_flg) {
case IPOPT_TS_TSONLY:
address_present = _B_FALSE;
data_len = sizeof (tsp->ipt_timestamp.ipt_time[0]);
rrflag = _B_TRUE;
break;
case IPOPT_TS_TSANDADDR:
address_present = _B_TRUE;
data_len = sizeof (tsp->ipt_timestamp.ipt_ta[0]);
rrflag = _B_TRUE;
break;
case IPOPT_TS_PRESPEC:
case 3:
address_present = _B_TRUE;
data_len = sizeof (tsp->ipt_timestamp.ipt_ta[0]);
rrflag = _B_FALSE;
break;
default:
Printf("(Bad flag value: 0x%x)", tsp->ipt_flg);
return;
}
if (tsp->ipt_oflw > 0)
Printf("(Overflow: %d) ", tsp->ipt_oflw);
length -= 4;
while (length > 0) {
if (length < data_len)
break;
if ((tsp->ipt_ptr == ts_index * data_len + 5) && rrflag) {
Printf(" (End of record)");
break;
}
if (address_present) {
bcopy(&tsp->ipt_timestamp.ipt_ta[ts_index].ipt_addr,
&addr, sizeof (addr));
Printf("%s: ", pr_name((char *)&addr, AF_INET));
bcopy(&tsp->ipt_timestamp.ipt_ta[ts_index].ipt_time,
&time, sizeof (time));
} else {
bcopy(&tsp->ipt_timestamp.ipt_time[ts_index],
&time, sizeof (time));
}
Printf("%d", ntohl(time));
if (tsp->ipt_ptr == ts_index * data_len + 5)
Printf("(Current)");
ts_index++;
length -= data_len;
if (length > 0)
Printf(", ");
}
}
static char *
pr_type(int icmp_type)
{
static struct icmptype_table ttab[] = {
{ICMP_ECHOREPLY, "Echo Reply"},
{1, "ICMP 1"},
{2, "ICMP 2"},
{ICMP_UNREACH, "Dest Unreachable"},
{ICMP_SOURCEQUENCH, "Source Quench"},
{ICMP_REDIRECT, "Redirect"},
{6, "ICMP 6"},
{7, "ICMP 7"},
{ICMP_ECHO, "Echo"},
{ICMP_ROUTERADVERT, "Router Advertisement"},
{ICMP_ROUTERSOLICIT, "Router Solicitation"},
{ICMP_TIMXCEED, "Time Exceeded"},
{ICMP_PARAMPROB, "Parameter Problem"},
{ICMP_TSTAMP, "Timestamp"},
{ICMP_TSTAMPREPLY, "Timestamp Reply"},
{ICMP_IREQ, "Info Request"},
{ICMP_IREQREPLY, "Info Reply"},
{ICMP_MASKREQ, "Netmask Request"},
{ICMP_MASKREPLY, "Netmask Reply"}
};
int i;
for (i = 0; i < A_CNT(ttab); i++) {
if (ttab[i].type == icmp_type)
return (ttab[i].message);
}
return ("OUT-OF-RANGE");
}