/*int maxTTL = MaxHost-1; */ /* max you can go is 255 hops */
int maxTTL = 30; /* inline with traceroute */
/* end ttl window stuff. */
+int remoteport = 80; /* for TCP tracing */
+int timeout = 10 * 1000000; /* for TCP tracing */
/* default display field(defined by key in net.h) and order */
{ "first-ttl", 1, 0, 'f' }, /* -f & -m are borrowed from traceroute */
{ "max-ttl", 1, 0, 'm' },
{ "udp", 0, 0, 'u' }, /* UDP (default is ICMP) */
+ { "tcp", 0, 0, 'T' }, /* TCP (default is ICMP) */
+ { "port", 1, 0, 'P' }, /* target port number for TCP */
+ { "timeout", 1, 0, 'Z' }, /* timeout for TCP sockets */
{ "inet", 0, 0, '4' }, /* IPv4 only */
{ "inet6", 0, 0, '6' }, /* IPv6 only */
{ "aslookup", 0, 0, 'z' }, /* Do AS lookup */
while(1) {
/* added f:m:o: byMin */
opt = getopt_long(argc, argv,
- "vhrwxtglpo:B:i:c:s:Q:ena:f:m:ubz46", long_options, NULL);
+ "vhrwxtglpo:B:i:c:s:Q:ena:f:m:uTP:Zbz46", long_options, NULL);
if(opt == -1)
break;
}
break;
case 'u':
+ if (mtrtype != IPPROTO_ICMP) {
+ fprintf(stderr, "-u and -T are mutually exclusive.\n");
+ exit(EXIT_FAILURE);
+ }
mtrtype = IPPROTO_UDP;
break;
+ case 'T':
+ if (mtrtype != IPPROTO_ICMP) {
+ fprintf(stderr, "-u and -T are mutually exclusive.\n");
+ exit(EXIT_FAILURE);
+ }
+ mtrtype = IPPROTO_TCP;
+ break;
case 'b':
show_ips = 1;
break;
+ case 'P':
+ remoteport = atoi(optarg);
+ if (remoteport > 65535 || remoteport < 1) {
+ fprintf(stderr, "Illegal port number.\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'Z':
+ timeout = atoi(optarg);
+ timeout *= 1000000;
+ break;
case '4':
af = AF_INET;
break;
}
if (PrintHelp) {
- printf("usage: %s [-hvrwctglspniu46] [--help] [--version] [--report]\n"
+ printf("usage: %s [-hvrwctglspniuT46] [--help] [--version] [--report]\n"
"\t\t[--report-wide] [--report-cycles=COUNT] [--curses] [--gtk]\n"
"\t\t[--raw] [--split] [--mpls] [--no-dns] [--show-ips]\n"
"\t\t[--address interface] [--aslookup]\n" /* BL */
"\t\t[--psize=bytes/-s bytes]\n" /* ok */
- "\t\t[--report-wide|-w] [-u]\n" /* rew */
+ "\t\t[--report-wide|-w] [-u|-T] [--port=PORT] [--timeout=SECONDS]\n" /* rew */
"\t\t[--interval=SECONDS] HOSTNAME [PACKETSIZE]\n", argv[0]);
exit(0);
}
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
#include <netinet/in.h>
#include <memory.h>
#include <unistd.h>
uint16 checksum;
};
+/* Structure of an TCP header, as far as we need it. */
+struct TCPHeader {
+ uint16 srcport;
+ uint16 dstport;
+ uint32 seq;
+};
+
/* Structure of an IPv4 UDP pseudoheader. */
struct UDPv4PHeader {
uint32 saddr;
int transit;
int saved_seq;
struct timeval time;
+ int socket;
};
extern int tos; /* type of service set in ping packet*/
extern int af; /* address family of remote target */
extern int mtrtype; /* type of query packet used */
+extern int remoteport; /* target port for TCP tracing */
+extern int timeout; /* timeout for TCP connections */
/* return the number of microseconds to wait before sending the next
ping */
}
-int new_sequence(int index)
+void save_sequence(int index, int seq)
{
- static int next_sequence = MinSequence;
- int seq;
-
- seq = next_sequence++;
- if (next_sequence >= MaxSequence)
- next_sequence = MinSequence;
-
sequence[seq].index = index;
sequence[seq].transit = 1;
sequence[seq].saved_seq = ++host[index].xmit;
host[index].up = 0;
host[index].sent = 1;
net_save_xmit(index);
-
+}
+
+int new_sequence(int index)
+{
+ static int next_sequence = MinSequence;
+ int seq;
+
+ seq = next_sequence++;
+ if (next_sequence >= MaxSequence)
+ next_sequence = MinSequence;
+
+ save_sequence(index, seq);
+
return seq;
}
+/* Attempt to connect to a TCP port with a TTL */
+void net_send_tcp(int index)
+{
+ int ttl, s;
+ int opt = 1;
+ int port;
+ struct sockaddr_storage local;
+ struct sockaddr_storage remote;
+ struct sockaddr_in *local4 = (struct sockaddr_in *) &local;
+ struct sockaddr_in6 *local6 = (struct sockaddr_in6 *) &local;
+ struct sockaddr_in *remote4 = (struct sockaddr_in *) &remote;
+ struct sockaddr_in6 *remote6 = (struct sockaddr_in6 *) &remote;
+ socklen_t len;
+
+ ttl = index + 1;
+
+ s = socket(af, SOCK_STREAM, 0);
+ if (s < 0) {
+ display_clear();
+ perror("socket()");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&local, 0, sizeof (local));
+ memset(&remote, 0, sizeof (remote));
+ local.ss_family = af;
+ remote.ss_family = af;
+
+ switch (af) {
+ case AF_INET:
+ addrcpy((void *) &local4->sin_addr, (void *) &ssa4->sin_addr, af);
+ addrcpy((void *) &remote4->sin_addr, (void *) remoteaddress, af);
+ remote4->sin_port = htons(remoteport);
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addrcpy((void *) &local6->sin6_addr, (void *) &ssa6->sin6_addr, af);
+ addrcpy((void *) &remote6->sin6_addr, (void *) remoteaddress, af);
+ remote6->sin6_port = htons(remoteport);
+ break;
+#endif
+ }
+
+ if (bind(s, (struct sockaddr *) &local, sizeof (local))) {
+ display_clear();
+ perror("bind()");
+ exit(EXIT_FAILURE);
+ }
+
+ len = sizeof (local);
+ if (getsockname(s, (struct sockaddr *) &local, &len)) {
+ display_clear();
+ perror("getsockname()");
+ exit(EXIT_FAILURE);
+ }
+
+ opt = 1;
+ if (ioctl(s, FIONBIO, &opt)) {
+ display_clear();
+ perror("ioctl FIONBIO");
+ exit(EXIT_FAILURE);
+ }
+
+ switch (af) {
+ case AF_INET:
+ if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof (ttl))) {
+ display_clear();
+ perror("setsockopt IP_TTL");
+ exit(EXIT_FAILURE);
+ }
+ if (setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof (tos))) {
+ display_clear();
+ perror("setsockopt IP_TOS");
+ exit(EXIT_FAILURE);
+ }
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof (ttl))) {
+ display_clear();
+ perror("setsockopt IP_TTL");
+ exit(EXIT_FAILURE);
+ }
+ break;
+#endif
+ }
+
+ switch (local.ss_family) {
+ case AF_INET:
+ port = ntohs(local4->sin_port);
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ port = ntohs(local6->sin6_port);
+ break;
+#endif
+ default:
+ display_clear();
+ perror("unknown AF?");
+ exit(EXIT_FAILURE);
+ }
+
+ save_sequence(index, port);
+ gettimeofday(&sequence[port].time, NULL);
+ sequence[port].socket = s;
+
+ connect(s, (struct sockaddr *) &remote, sizeof (remote));
+}
/* Attempt to find the host at a particular number of hops away */
void net_send_query(int index)
{
+ if (mtrtype == IPPROTO_TCP) {
+ net_send_tcp(index);
+ return;
+ }
+
/*ok char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/
char packet[MAXPACKET];
struct IPHeader *ip = (struct IPHeader *) packet;
return;
sequence[seq].transit = 0;
+ if (sequence[seq].socket > 0) {
+ close(sequence[seq].socket);
+ sequence[seq].socket = 0;
+ }
+
index = sequence[seq].index;
totusec = (now.tv_sec - sequence[seq].time.tv_sec ) * 1000000 +
int num;
struct ICMPHeader *header = NULL;
struct UDPHeader *udpheader = NULL;
+ struct TCPHeader *tcpheader = NULL;
struct timeval now;
ip_t * fromaddress = NULL;
int echoreplytype = 0, timeexceededtype = 0, unreachabletype = 0;
sequence = ntohs(udpheader->dstport);
}
break;
+
+ case IPPROTO_TCP:
+ if (header->type == timeexceededtype || header->type == unreachabletype) {
+ switch ( af ) {
+ case AF_INET:
+
+ if ((size_t) num < sizeof(struct IPHeader) +
+ sizeof(struct ICMPHeader) +
+ sizeof (struct IPHeader) +
+ sizeof (struct TCPHeader))
+ return;
+ tcpheader = (struct TCPHeader *)(packet + sizeof (struct IPHeader) +
+ sizeof (struct ICMPHeader) +
+ sizeof (struct IPHeader));
+
+ if(num > 160)
+ decodempls(num, packet, &mpls, 156);
+
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ if ( num < sizeof (struct ICMPHeader) +
+ sizeof (struct ip6_hdr) + sizeof (struct TCPHeader) )
+ return;
+ tcpheader = (struct TCPHeader *) ( packet +
+ sizeof (struct ICMPHeader) +
+ sizeof (struct ip6_hdr) );
+
+ if(num > 140)
+ decodempls(num, packet, &mpls, 136);
+
+ break;
+#endif
+ }
+ sequence = ntohs(tcpheader->srcport);
+ }
+ break;
}
if (sequence)
for (at = 0; at < MaxSequence; at++) {
sequence[at].transit = 0;
+ if (sequence[at].socket > 0) {
+ close(sequence[at].socket);
+ sequence[at].socket = 0;
+ }
}
gettimeofday(&reset, NULL);
}
}
}
+
+/* Add open sockets to select() */
+void net_add_fds(fd_set *writefd, int *maxfd)
+{
+ int at, fd;
+ for (at = 0; at < MaxSequence; at++) {
+ fd = sequence[at].socket;
+ if (fd > 0) {
+ FD_SET(fd, writefd);
+ if (fd >= *maxfd)
+ *maxfd = fd + 1;
+ }
+ }
+}
+
+/* check if we got connection or error on any fds */
+void net_process_fds(fd_set *writefd)
+{
+ int at, fd, r;
+ struct timeval now;
+ uint64_t unow, utime;
+
+ /* Can't do MPLS decoding */
+ struct mplslen mpls;
+ mpls.labels = 0;
+
+ gettimeofday(&now, NULL);
+ unow = now.tv_sec * 1000000L + now.tv_usec;
+
+ for (at = 0; at < MaxSequence; at++) {
+ fd = sequence[at].socket;
+ if (fd > 0 && FD_ISSET(fd, writefd)) {
+ r = write(fd, "G", 1);
+ /* if write was successful, or connection refused we have
+ * (probably) reached the remote address. Anything else happens to the
+ * connection, we write it off to avoid leaking sockets */
+ if (r == 1 || errno == ECONNREFUSED)
+ net_process_ping(at, mpls, remoteaddress, now);
+ else if (errno != EAGAIN) {
+ close(fd);
+ sequence[at].socket = 0;
+ }
+ }
+ if (fd > 0) {
+ utime = sequence[at].time.tv_sec * 1000000L + sequence[at].time.tv_usec;
+ if (unow - utime > timeout) {
+ close(fd);
+ sequence[at].socket = 0;
+ }
+ }
+ }
+}
+
+/* for GTK frontend */
+void net_harvest_fds(void)
+{
+ fd_set writefd;
+ int maxfd = 0;
+ struct timeval tv;
+
+ FD_ZERO(&writefd);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ net_add_fds(&writefd, &maxfd);
+ select(maxfd, NULL, &writefd, NULL, &tv);
+ net_process_fds(&writefd);
+}
\ No newline at end of file