/****************************************************************************
* Pathneck: locating network path bottlenecks
* Copyright (C) 2004
* Ningning Hu and the Carnegie Mellon University
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License (in the COPYING file) for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The GetCannonicalInfo() function used by this file is copied from
* sting's code, which is under BSD license.
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#if defined(_BSD) || defined(__APPLE__)
#include <sys/param.h>
#else
#include <values.h>
#endif
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h> /* _BSD: should be before resolv.h */
#include <resolv.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include "pathneck.h"
#include "planetlab.h"
#include "get-line.h"
#include "util.h"
#include "choke.h"
struct ip *outip; /* last output (udp) packet */
struct udphdr *outudp; /* last output (udp) packet */
struct icmp *outicmp;
struct outdata *outdata; /* last output (udp) packet */
u_short ident;
u_short port = 42768 + 666; /* start udp dest port # for probe packets */
int debug = 0;
int verbose = 0;
int delay_num = 0;
int udp_probing_size = PKT_SIZE;
int udp_pkt_num = UDP_TRAIN_LEN;
int end_pkt_num = 30;
int win_size = 0;
int planetlab = 0;
int on_line_processing = 0;
int icmp_probing = 0; /* set it with 1 means using ICMP packets to probe */
int dns_lookup = 0; /* x: enable the hostname conversion */
int dump_send_time = 0; /* dump the send_time2 array */
/* config filename: $HOME/.patheneck.$hostname */
char conf_file[256];
FILE * conf_fp = NULL;
char info_line1[256];
char info_line2[1024];
int udp_sock;
int icmp_sock;
int udpicmp_sock;
int udp_port = 31415;
uint32_t self_ip = 0;
uint32_t ip;
char dst_hostname[MAXHOSTNAMELEN];
char dst_ip_str[16];
char self_hostname[MAXHOSTNAMELEN];
char self_ip_str[16];
/* the received path info, ordered by receiving time */
struct ip_icmp_hdr time_path[MAX_REC];
int path_i = 0;
/* the received path info, ordered by ttl */
struct time_arr ip_path[MAX_TTL];
int ip_path_len = 0;
/* record the sending time for all the packets, including the load pkts */
double send_time[MAX_REC + MAX_UDP_NUM];
double send_time2[MAX_REC + MAX_UDP_NUM];
int send_i2 = 0;
/* used to record one time of receiving operations */
char path_rec[MAX_REC][256];
double arr_time[MAX_REC];
int rec_i = 0;
/* used for recording the responses from the destinations */
char rtt_rec[MAX_RTT_NUM][256];
double rtt_arr_time[MAX_RTT_NUM];
double avg_rtt = 0;
uint32_t rtt_dst;
int rtt_i = 0;
void usage()
{
printf("%s\n", USAGE_TXT);
exit(0);
}
/* borrowed from sting's code */
int GetCannonicalInfo(char *string, char name[MAXHOSTNAMELEN],
uint32_t *address, char ip_str[16])
{
struct hostent *hp;
struct in_addr in_a;
/* Is string in dotted decimal format? */
#ifdef SUN
if ((*address = inet_addr(string)) == INADDR_BROADCAST) {
#else
if ((*address = inet_addr(string)) == INADDR_NONE) {
#endif
/* No, then lookup IP address */
if ((hp = gethostbyname(string)) == NULL) {
/* Can't find IP address */
printf("ERROR: couldn't obtain address for %s\n", string);
return -1;
} else {
strncpy(name, hp->h_name, MAXHOSTNAMELEN-1);
memcpy((void *)address, (void *)hp->h_addr, hp->h_length);
in_a.s_addr = *address;
strcpy(ip_str, inet_ntoa(in_a));
}
} else {
strcpy(ip_str, string);
if ((hp = gethostbyaddr((char *)address,
sizeof(*address), AF_INET)) == NULL) {
/* Can't get cannonical hostname, so just use input string */
strncpy(name, string, MAXHOSTNAMELEN - 1);
} else {
strncpy(name, hp->h_name, MAXHOSTNAMELEN - 1);
}
}
return 0;
}
int create_raw_socket(int port, int proto)
{
int sock, yes=1;
struct sockaddr_in address;
sock = socket(AF_INET, SOCK_RAW, proto);
if (sock < 0) {
perror("socket");
exit(1);
}
if(setsockopt(sock, 0, IP_HDRINCL, &yes, sizeof(yes)) < 0) {
perror("IP_HDRINCL");
exit(1);
}
if (port <= 0)
return sock;
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
address.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) {
perror("bind");
exit(1);
}
return sock;
}
/* send out one raw udp/icmp packet */
void send_echo_udp(int seq, int size, int ttl, uint32_t dst_ip)
{
struct timeval t1;
struct timezone tz;
struct sockaddr_in addr;
register struct udpip_header *ui, *oui;
struct ip tip;
outip->ip_ttl = ttl;
#ifdef _BSD
outip->ip_id = ident + seq;
outip->ip_len = size;
outip->ip_off = 0;
#else
outip->ip_id = htons(ident + seq);
outip->ip_len = htons(size);
outip->ip_off = htons(0);
#endif
/* In most cases, the kernel will recalculate the ip checksum.
* But we must do it anyway so that the udp checksum comes out
* right.
*/
outip->ip_sum =
in_cksum((u_short *)outip, sizeof(*outip));
if (outip->ip_sum == 0)
outip->ip_sum = 0xffff;
/* Payload */
outdata->seq = seq;
outdata->ttl = ttl;
(void)gettimeofday(&t1, &tz);
outdata->tv = t1;
send_time[seq] = (double)t1.tv_sec + (double)t1.tv_usec / 1000000;
send_time2[send_i2] = (double)t1.tv_sec + (double)t1.tv_usec / 1000000;
send_i2 ++;
if (!icmp_probing) {
/* Checksum (we must save and restore ip header) */
tip = *outip;
ui = (struct udpip_header *)outip;
oui = (struct udpip_header *)&tip;
/* Easier to zero and put back things that are ok */
memset((char *)ui, 0, sizeof(ui->ui_i));
ui->ui_src = oui->ui_src;
ui->ui_dst = oui->ui_dst;
ui->ui_pr = oui->ui_pr;
#if defined SUN || defined _BSD || defined __APPLE__
outudp->uh_dport = htons(port + seq);
outudp->uh_ulen = htons((u_short)(size - (sizeof(*outip))));
ui->ui_len = outudp->uh_ulen;
outudp->uh_sum = 0;
/* TODO: set the checksum to 0 will trigger last hop's reply,
* but we filter them anyway */
outudp->uh_sum = in_cksum((u_short *)ui, size);
if (outudp->uh_sum == 0)
outudp->uh_sum = 0xffff;
#else /* Linux UDP packets */
outudp->dest = htons(port + seq);
outudp->len = htons((u_short)(size - (sizeof(*outip))));
ui->ui_len = outudp->len;
outudp->check = 0;
/* TODO: set the checksum to 0 will trigger last hop's reply,
* but we filter them anyway */
outudp->check = in_cksum((u_short *)ui, size);
if (outudp->check == 0)
outudp->check = 0xffff;
#endif
*outip = tip;
} else { /* send ICMP probing packets */
outicmp->icmp_seq = htons(port+seq);
/* the magic number here for packet matching */
outicmp->icmp_mask = htonl(MAGIC_NUM);
outicmp->icmp_cksum = 0;
outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
size - sizeof(*outip));
if (outicmp->icmp_cksum == 0)
outicmp->icmp_cksum = 0xffff;
}
outip->ip_dst.s_addr = dst_ip;
/* we must change port number each time, this will be used for
* identification */
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = dst_ip;
if (planetlab && icmp_probing) {
/* Planetlab nodes doesn't allows udp_sock to send ICMP raw
* packets */
if (sendto(icmp_sock, outip, size, 0, (struct sockaddr*)&addr, sizeof(addr)) < 0)
perror(ip2str(ip));
} else {
if (sendto(udp_sock, outip, size, 0, (struct sockaddr*)&addr, sizeof(addr)) < 0)
perror(ip2str(ip));
}
}
/* zero all the global variables */
void clean_path()
{
int i, k;
rec_i = 0;
path_i = 0;
ip_path_len = 0;
memset(time_path, 0, sizeof(struct ip_icmp_hdr) * MAX_REC);
memset(path_rec, 0, MAX_REC);
info_line1[0] = 0;
info_line2[0] = 0;
for (i=0; i<MAX_TTL; i++) {
for (k=0; k<TRAIN_LEN; k++) {
ip_path[i].index[k] = -1;
ip_path[i].cnt = 0;
ip_path[i].ip = 0;
ip_path[i].avg_gap = 0;
ip_path[i].cong_order = 0;
}
}
for (i=0; i<MAX_REC; i++) {
send_time[i] = 0;
arr_time[i] = 0;
}
memset(rtt_rec, 0, MAX_RTT_NUM * 256);
memset(rtt_arr_time, 0, MAX_RTT_NUM * sizeof(double));
avg_rtt = 0;
rtt_dst = 0;
rtt_i = 0;
}
void set_udp_header()
{
register u_char *outp = (u_char *)(outip + 1);
outip->ip_p = IPPROTO_UDP;
outudp = (struct udphdr *)outp;
// outudp->source = htons(ident);
#if defined SUN || defined _BSD || defined __APPLE__
outudp->uh_sport = htons(udp_port);
#else
outudp->source = htons(udp_port);
#endif
outdata = (struct outdata *)(outudp + 1);
}
void set_icmp_header()
{
register u_char *outp = (u_char *)(outip + 1);
outip->ip_p = IPPROTO_ICMP;
outicmp = (struct icmp *)outp;
outicmp->icmp_type = ICMP_ECHO;
// outicmp->icmp_code = 0;
/* this field is important for Planetlab nodes, must be the same port
* with the corresponding packets */
outicmp->icmp_id = htons(udp_port);
outdata = (struct outdata *)(outp + 8); /* XXX magic number */
}
void init()
{
register u_char *outp = (u_char *)(outip + 1);
if (!icmp_probing) {
udp_sock = create_raw_socket(udp_port, IPPROTO_UDP);
icmp_sock = create_raw_socket(udp_port, IPPROTO_ICMP);
} else {
udp_sock = create_raw_socket(udp_port, IPPROTO_ICMP);
icmp_sock = udp_sock;
}
if (planetlab)
udpicmp_sock = create_raw_socket(udp_port, IPPROTO_ICMP_UDP);
else
udpicmp_sock = create_raw_socket(udp_port, IPPROTO_ICMP);
/* init the shared pkt header structures */
outip = (struct ip *)malloc(MAX_ECHO);
if (outip == NULL) {
perror("malloc");
exit(1);
}
memset((char *)outip, 0, MAX_ECHO);
outip->ip_v = IPVERSION;
outip->ip_tos = 0;
outp = (u_char *)(outip + 1);
outip->ip_dst.s_addr = ip;
outip->ip_src.s_addr = self_ip;
outip->ip_hl = (outp - (u_char *)outip) >> 2;
ident = (getpid() & 0xffff) | 0x8000;
if (!icmp_probing)
set_udp_header();
else
set_icmp_header();
}
/* output the probing results */
void dump_route()
{
int i, j, k1, k2;
double rtt1, rtt2, rtt;
double bw;
char hostname[MAXHOSTNAMELEN], ipstr[16], my_ipstr[16];
uint32_t cur_ip;
if (on_line_processing)
get_choke();
printf("%s %d\n", info_line1, delay_num);
printf("%s", info_line2);
/* no valid reponse */
if (ip_path_len == 0 && !ip_path[0].ip) {
printf("# no hop reponses\n\n");
return;
}
printf("\n");
j = 0;
for (i=0; i<=ip_path_len; i++) {
if (!dns_lookup) {
strcpy(hostname, ip2str(ip_path[i].ip));
} else {
strcpy(my_ipstr, ip2str(ip_path[i].ip));
GetCannonicalInfo(my_ipstr, hostname, &cur_ip, ipstr);
}
k1 = ip_path[i].index[0];
rtt1 = time_path[k1].rtime - time_path[k1].stime;
k2 = ip_path[i].index[1];
rtt2 = (time_path[k2].rtime - time_path[k2].stime);
rtt = (rtt1 + rtt2) / 2;
/* the basic output */
printf("%02d %7.3f %15s %6d",
i, rtt1 * 1000, ip2str(ip_path[i].ip),
(int)(ip_path[i].avg_gap * 1000000));
/* if require on line detection*/
if (on_line_processing) {
if (i == node[j].index) {
printf(" %6d", node[j].gap1);
if (selected[j])
printf(" %c", selected[j][1]);
else
printf(" %c", '.');
bw = ((double)udp_probing_size * udp_pkt_num * 8) / (1000000 * (double)ip_path[i].avg_gap);
if (node[j].bw_flag > 0)
printf(" %7.3f ub", bw);
else if (node[j].bw_flag < 0)
printf(" %7.3f lb", bw);
else
printf(" %7.3f uk", 0.0);
j ++;
} else {
printf(" %6d . %7.3f uk", 0, 0.0);
}
}
/* IP -> DNS name lookup */
if (dns_lookup)
printf(" %s", hostname);
printf("\n");
}
/* confidence information */
if (on_line_processing) {
printf("conf =");
for (i=0; i<num_choke; i++)
printf(" %.3f", conf[i]);
printf("\n");
}
printf("\n");
/* dump rtt */
if (avg_rtt) {
printf("rtt = %.3f ( %s )\n",
avg_rtt * 1000, ip2str(rtt_dst));
printf("\n");
}
if (dump_send_time) {
for (i = 0; i<send_i2; i++) {
printf("%03d %.6f\n", i, send_time2[i]);
}
printf("\n");
}
}
/* only receive and store, avoid on-line processing as much as possible */
void recv_pkts(int last)
{
char buffer[1024];
int len, addrlen;
struct sockaddr_in addr;
#ifdef _BSD
fd_set rfds;
struct timeval tv;
int retval;
#endif
struct iphdr * iphdr;
struct icmp * icmp;
int cnt = 0;
double pre_time, cur_time;
/* receive */
pre_time = get_time();
cur_time = pre_time;
cnt = 0;
while (cnt < 2*end_pkt_num) {
#ifdef _BSD
FD_ZERO(&rfds);
FD_SET(udpicmp_sock, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(udpicmp_sock + 1, &rfds, NULL, NULL, &tv);
if (!(retval && FD_ISSET(udpicmp_sock, &rfds))) {
if (!last) return;
cur_time = get_time();
if (cur_time - pre_time > 3)
break;
continue;
}
#endif
addrlen = sizeof(addr);
memset(buffer, 0, sizeof(buffer));
len=recvfrom(udpicmp_sock, buffer, sizeof(buffer), MSG_DONTWAIT,
(struct sockaddr*)&addr, &addrlen);
if (len > 0) {
iphdr = (struct iphdr *)buffer;
icmp = (struct icmp *)(buffer + (iphdr->ihl<<2));
/* icmp echoreply is supposed to be from the last hop */
if (icmp->icmp_type == ICMP_ECHOREPLY) {
/* make sure the data part is match the magic number,
* o.w., it is not our packets */
if (ntohl(icmp->icmp_mask) != MAGIC_NUM)
continue;
/* if "-c" is specified, rtt_i could exceed MAX_RTT_NUM */
if (rtt_i < MAX_RTT_NUM) {
memcpy(rtt_rec[rtt_i], buffer, len);
rtt_arr_time[rtt_i] = get_time();
pre_time = rtt_arr_time[rtt_i];
rtt_i ++;
}
continue;
}
if (icmp->icmp_type != ICMP_TIMXCEED)
continue;
/* need to check the Internet head to make sure it is
* our packets */
iphdr = (struct iphdr *)(buffer + (iphdr->ihl<<2) + 8);
if (iphdr->daddr != ip)
continue;
memcpy(path_rec[rec_i], buffer, len);
arr_time[rec_i] = get_time();
pre_time = arr_time[rec_i];
rec_i ++;
if (rec_i >= MAX_REC) break;
if (debug)
printf("rec_i = %d\n", rec_i);
cnt ++;
}
else {
if (!last) return;
cur_time = get_time();
if (cur_time - pre_time > 3)
break;
continue;
}
}
}
/* send out a train with ttl */
void send_pkts(uint32_t ip, int delay_num)
{
int j, k, di;
double tmp = 133333.000333;
double stime, etime;
struct timeval tv;
/* allow recv_pkts() to resume */
tv.tv_sec = 0;
tv.tv_usec = 300000;
select(0, NULL, NULL, NULL, &tv);
stime = get_time();
/* for udp probing, send max_num_rtt icmp echo packets to
* measure rtt */
if (!icmp_probing && !planetlab) {
icmp_probing = 1;
set_icmp_header();
for (j=1; j<=MAX_RTT_NUM; j++) {
k = end_pkt_num * TRAIN_LEN + 2 + udp_pkt_num + j;
send_echo_udp(k, 60, 100, ip);
}
/* reset for udp probing */
icmp_probing = 0;
set_udp_header();
}
/* the head measurement packets */
for (j=1; j<=end_pkt_num; j++) {
k = j * TRAIN_LEN;
send_echo_udp(k, 60, j, ip);
}
/* the load packets */
for (j=0; j<udp_pkt_num; j++) {
if (debug) {
printf("%d\n", j);
}
recv_pkts(0);
/* load packet, k doesn't change to avoid using too much
* destination ports, and avoid triggering the alarm */
k = 0;
send_echo_udp(k, udp_probing_size, 100, ip);
if (j == udp_pkt_num - 1)
break;
/* src gap generation */
for (di=0; di<delay_num; di++) {
tmp = tmp * 7;
tmp = tmp / 13;
if (di % 20 == 0)
recv_pkts(0);
}
}
/* the end measurement packets */
for (j=1; j<=end_pkt_num; j++) {
k = (end_pkt_num-j+1) * TRAIN_LEN + 1;
send_echo_udp(k, 60, end_pkt_num-j+1, ip);
}
etime = get_time();
recv_pkts(1);
sprintf(info_line1, "%f %s %d %d", stime,
ip2str(ip), udp_probing_size, udp_pkt_num);
}
/* store the rtt measurment (echo reply) packets, used by store() */
void store_rtt()
{
int i, j;
struct iphdr *iphdr;
struct icmp *icmp;
double cur_rtt;
double sum_rtt = 0;
int rtt_cnt = 0;
/* store the rtt packets */
for (i=0; i<rtt_i; i++) {
iphdr = (struct iphdr *)&(rtt_rec[i]);
icmp = (struct icmp *)((char *)(rtt_rec[i])+(iphdr->ihl<<2));
/* echoreply packet can only be generated by
* icmp probing packets */
j = ntohs(icmp->icmp_seq) - port;
if (j >= 0) {
cur_rtt = rtt_arr_time[i] - send_time[j];
rtt_dst = iphdr->saddr;
sum_rtt += cur_rtt;
/* we only compute the first 5 rtt echo reply packets,
* later reply tends to have larger error due to icmp packet
* generation delay */
if (++rtt_cnt > MAX_RTT_NUM) break;
if (debug)
printf("%2d rtt: %.3f, %s\n", j, cur_rtt * 1000, ip2str(rtt_dst));
}
else if (debug)
printf("wrong seq number in the echo reply pkt: j = %d\n", j);
}
if (rtt_cnt)
avg_rtt = sum_rtt / rtt_cnt;
}
/* check if this IP already appears for an ealier hop */
int exist_ip_before(uint32_t in_ip)
{
int i;
for (i=0; i<=ip_path_len; i++)
if (ip_path[i].ip == in_ip)
return 1;
return 0;
}
/* store the time exceeds icmp pkts */
void store()
{
int i, j, k, k1, k2;
struct iphdr *iphdr;
struct icmp *icmp;
struct udphdr *udphdr;
struct icmp *icmphdr;
/* store the headers */
for (i=0; i<rec_i; i++) {
iphdr = (struct iphdr *)&(path_rec[i]);
icmp = (struct icmp *)((char *)(path_rec[i])+(iphdr->ihl<<2));
memcpy(&(time_path[path_i].iph), iphdr, sizeof(struct iphdr));
memcpy(&(time_path[path_i].icmph), icmp, sizeof(struct icmp));
time_path[path_i].rtime = arr_time[i];
if (!icmp_probing) {
udphdr = (struct udphdr *)((char *)icmp + 8 + sizeof(struct ip));
#if defined SUN || defined _BSD || defined __APPLE__
j = ntohs(udphdr->uh_dport) - port;
#else
j = ntohs(udphdr->dest) - port;
#endif
} else {
icmphdr = (struct icmp *)((char *)icmp + 8 + sizeof(struct ip));
j = ntohs(icmphdr->icmp_seq) - port;
}
/* @@ when there is route loop, j could be < 0 */
if (j < 0 || j >= MAX_REC + MAX_UDP_NUM)
continue;
time_path[path_i].stime = send_time[j];
k = j % TRAIN_LEN;
j = (int) j / TRAIN_LEN - 1;
/* @@ this is also used to deal with route loop */
if (j > ip_path_len && exist_ip_before(iphdr->saddr)) {
sprintf(info_line2 + strlen(info_line2), "%d %s loop\n",
j, ip2str(iphdr->saddr));
continue;
}
if (debug)
printf("%d %d %f %s\n", j, k, arr_time[i],
ip2str(iphdr->saddr));
ip_path[j].index[k] = path_i;
ip_path[j].cnt ++;
if (!ip_path[j].ip) {
ip_path[j].ip = iphdr->saddr;
} else if (iphdr->saddr != ip_path[j].ip) {
ip_path[j].as = -1;
sprintf(info_line2 + strlen(info_line2), "%d %s ", j, ip2str(iphdr->saddr));
sprintf(info_line2 + strlen(info_line2), "%s\n", ip2str(ip_path[j].ip));
}
if (j > ip_path_len)
ip_path_len = j;
path_i ++;
}
rec_i = 0;
for (i=0; i<=ip_path_len; i++) {
k1 = ip_path[i].index[0];
k2 = ip_path[i].index[1];
if (k1>=0 && k2>=k1)
ip_path[i].avg_gap = time_path[k2].rtime - time_path[k1].rtime;
}
store_rtt();
}
void probe_once()
{
if (verbose)
printf("probe_once() with [%d %d]\n", udp_pkt_num, delay_num);
clean_path();
send_pkts(ip, delay_num);
if (rec_i > 0) store();
}
int main(int argc, char * argv[])
{
int opt;
int sock;
struct sockaddr_in src_addr;
#ifndef SUN
struct in_addr in_s;
#endif
int src_size;
/* we have too many options here, but SUN generally doesn't
* support getopt_long, so have to live with these short options */
while ((opt = getopt(argc, argv, "e:i:l:s:y:coptxdvh")) != EOF) {
switch ((char)opt) {
case 'e':
end_pkt_num = atoi(optarg);
break;
case 'i':
self_ip = inet_addr(optarg);
break;
case 'l':
udp_pkt_num = atoi(optarg);
break;
case 's':
udp_probing_size = atoi(optarg);
break;
case 'y':
delay_num = atoi(optarg);
break;
case 'c':
icmp_probing = 1;
break;
case 'o':
on_line_processing = 1;
break;
case 'p':
planetlab = 1;
break;
case 't':
dump_send_time = 1;
break;
case 'x':
dns_lookup = 1;
break;
case 'd':
debug = 1;
break;
case 'v':
verbose = 1;
break;
case 'h':
default:
usage();
}
}
switch (argc - optind) {
case 1:
#ifndef SUN
/* if it is IP, break immeadiately */
if (inet_aton(argv[optind], &in_s) != 0) {
strcpy(dst_ip_str, argv[optind]);
ip = in_s.s_addr;
break;
}
#else
ip = inet_addr(argv[optind]);
if (ip == -1)
ip = 0;
else
break;
#endif
/* otherwise, convert from hostname to IP */
if (GetCannonicalInfo(argv[optind], dst_hostname,
&ip, dst_ip_str) < 0)
exit(0);
break;
default:
usage();
}
if (!self_ip) {
if (gethostname(self_hostname, sizeof(self_hostname)) < 0) {
perror("gethostname() failed");
exit(1);
}
/* this method gives us the ip 0.0.0.0, but works so far */
sock = socket(AF_INET, SOCK_STREAM, 0);
src_size = sizeof(struct sockaddr);
getsockname(sock, (struct sockaddr *)&src_addr, &src_size);
self_ip = src_addr.sin_addr.s_addr;
close(sock);
}
init();
probe_once();
dump_route();
close(udp_sock);
close(udpicmp_sock);
/* keep "make" happy */
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1