📄 traceroute.c
字号:
/*traceroute--1060320113--徐大海 */#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#define __FAVOR_OPENSUSE#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/udp.h>#include <netinet/ip_icmp.h>/* some used constants - avoids Magic Numbers */#define BUF_SIZ 4096#define PORT 33434 /* standard for traceroute */#define WAITTIME 3#define NQUERIES 3#define PACKETSIZE 28#define MAX_PACKETSIZE 65535#define PACKET_HEADER_LEN 28 /* IP-Header + ICMP-Header */#define MAX_TTL 30enum {LAST_PACKET = 1, INVALID_PACKET};#define VERSION "1.0"struct sockaddr_in target_addr;int display_ttl = 0, max_ttl = MAX_TTL, resolve = 1, port = PORT, nqueries = NQUERIES, verbose = 0, waittime = WAITTIME, packetsize = PACKETSIZE, id;char *hostname = NULL;char usage[]="Usage:traceroute[-dnrv] [-w wait] [-m maxttl] [-p port#] [-q nqueries] [-t tos] [-s src_addr] [-g gateway] host [data size]\n";/* send the udp datagram with the given ttl */int send_udp_packet(int sock, struct sockaddr_in addr, int ttl, int port){ char packet[MAX_PACKETSIZE]; addr.sin_port = htons(port); /* set the ttl-field of the header */ if (setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) { perror("setsockopt() failed"); return 1; } if (sendto(sock, packet, packetsize - PACKET_HEADER_LEN, 0, (struct sockaddr*)&addr, sizeof(addr)) == -1) { perror("sendto() failed"); return 2; } return 0;}/* this function is called when an ICMP messages arrives */int icmp_recvd(int icmp_socket, int ttl, int n, struct timeval *tv_start){ char buffer[BUF_SIZ]; static char name[BUF_SIZ]; int bytes; static u_long last_addr; struct icmp *icmp; struct udphdr *udp; struct ip *ip; struct timeval tv_end; struct hostent *host; u_long diff; bytes = read(icmp_socket, buffer, sizeof(buffer)); /* is it our packet? */ if (bytes >= 2 * sizeof(*ip) + sizeof(*icmp) + sizeof(*udp)) { udp = (struct udphdr*) (buffer+sizeof(*icmp)+2*sizeof(*ip)); if (udp->uh_sport != htons(id)) return INVALID_PACKET; } /* calculate the time the answer needed */ gettimeofday(&tv_end, NULL); diff = ((tv_end.tv_sec - tv_start->tv_sec) * 1000) + ((tv_end.tv_usec - tv_start->tv_usec) / 1000); ip = (struct ip*) buffer; icmp = (struct icmp*) (buffer + sizeof(*ip)); /* this is only called once per address */ if (last_addr != ip->ip_src.s_addr) { strcpy(name, inet_ntoa(ip->ip_src)); host = gethostbyaddr((char*) &ip->ip_src, sizeof(ip->ip_src), AF_INET); if (resolve && host) strcpy(name, host->h_name); printf("%s (%s)", name, inet_ntoa(ip->ip_src)); if (display_ttl) printf(" ttl=%i", ip->ip_ttl); last_addr = ip->ip_src.s_addr; } /* verbose output */ if (verbose) { putchar('\n'); putchar('\t'); switch(icmp->icmp_type) { case ICMP_ECHOREPLY: printf("ICMP_ECHOREPLY"); break; case ICMP_UNREACH: printf("ICMP_UNREACH"); break; case ICMP_SOURCEQUENCH: printf("ICMP_SOURCEQUENCH"); break; case ICMP_REDIRECT: printf("ICMP_REDIRECT"); break; case ICMP_ECHO: printf("ICMP_ECHO"); break; case ICMP_TIMXCEED: printf("ICMP_TIMXCEED"); break; case ICMP_PARAMPROB: printf("ICMP_PARAMPROB"); break; case ICMP_TSTAMP: printf("ICMP_TSTAMP"); break; case ICMP_TSTAMPREPLY: printf("ICMP_TSTAMPREPLY"); break; case ICMP_IREQ: printf("ICMP_IREQ"); break; case ICMP_IREQREPLY: printf("ICMP_IREQREPLY"); break; case ICMP_MASKREQ: printf("ICMP_MASKREQ"); break; case ICMP_MASKREPLY: printf("ICMP_MASKREPLY"); break; default: printf("unknown ICMP"); break; } printf(" from %s after", inet_ntoa(ip->ip_src)); } printf (" %lu ms", !diff?1:diff); fflush(stdout); /* finished? if so, we get something like ICMP_UNREACH */ if (icmp->icmp_type != ICMP_TIMXCEED) return LAST_PACKET; return 0;}/* the tracing-function */int trace(void){ struct hostent *host; int udp_socket, icmp_socket, ttl, ret = 0, i; struct in_addr addr; struct sockaddr_in source_addr; struct timeval tv, tv_start; fd_set fds; /* if it's an ip-address, ok. if not, we resolve it */ if (!inet_aton(hostname, &addr)) { if ( !(host = gethostbyname(hostname)) ) { herror("gethostbyname() failed"); return 1; } addr = *(struct in_addr*) host->h_addr; } target_addr.sin_addr = addr; target_addr.sin_family = AF_INET; printf("traceroute to %s (%s), %i hops max, %i byte packets\n", hostname, inet_ntoa(addr), max_ttl, packetsize); /* this is the sending socket */ if ( (udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket() failed"); return 2; } source_addr.sin_addr.s_addr = INADDR_ANY; source_addr.sin_port = htons(id); source_addr.sin_family = AF_INET; /* bind the source-port in order to distinguish the packets */ if (bind(udp_socket, (struct sockaddr*)&source_addr, sizeof(source_addr)) == -1) { perror("bind() failed"); return 3; } /* this socket receives the ICMP answers */ if ( (icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) { perror("socket() failed"); return 4; } for(ttl = 1; ttl <= max_ttl && (ret != LAST_PACKET); ttl++) { printf(" %i ", ttl); fflush(stdout); for (i = 0; i < nqueries; i++) { /* the start-time of our packet */ gettimeofday(&tv_start, NULL); if (send_udp_packet(udp_socket, target_addr, ttl, port + i)) return 5; /* sorry for the goto ;-) * we jump here if the received packet isn't for us */ invalid_packet: FD_ZERO(&fds); FD_SET(icmp_socket, &fds); tv.tv_sec = waittime; tv.tv_usec = 0; /* for the timeout */ select(icmp_socket + 1, &fds, 0, 0, &tv); if (FD_ISSET(icmp_socket, &fds)) { if ( (ret = icmp_recvd(icmp_socket, ttl, i, &tv_start)) == INVALID_PACKET) goto invalid_packet; } else printf(" *"); fflush(stdout); } putchar('\n'); } /* clean up a bit */ close(icmp_socket); close(udp_socket); return 0;}int main(int argc, char *argv[]){ int i; if (argc < 2) { printf(usage); exit(0); } id = (getpid() & 0x7fff) | 0x8000; /* getting the options and values */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-l")) { display_ttl = 1; continue; } if (!strcmp(argv[i], "-m")) { if (i + 1 < argc) max_ttl = atol(argv[++i]); else { printf(usage); exit(0); } continue; } if (!strcmp(argv[i], "-n")) { resolve = 0; continue; } if (!strcmp(argv[i], "-p")) { if (i + 1 < argc) port = atol(argv[++i]); else { printf(usage); exit(0); } continue; } if (!strcmp(argv[i], "-q")) { if (i + 1 < argc) nqueries = atol(argv[++i]); else { printf(usage); exit(0); } continue; } if (!strcmp(argv[i], "-v")) { verbose = 1; continue; } if (!strcmp(argv[i], "-w")) { if (i + 1 < argc) waittime = atol(argv[++i]); else { printf(usage); exit(0); } continue; } if (!hostname) { hostname = argv[i]; continue; } if( (packetsize = atol(argv[i])) != 0) continue; fprintf(stderr, "unknown option: %s\n", argv[i]); return 1; } /* well, less than only the headers isn't possible */ if (packetsize < PACKET_HEADER_LEN) { fprintf(stderr, "value of packetsize is too small! " "Use %i or more.\n", PACKET_HEADER_LEN); return 2; } /* let's do it */ return trace();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -