#define SPRAY #ifndef lint static char *rcsid = "@(#)$Header: trACESroute.c,v 6.0 GOLD 1999/11/15 gavron(gavron@aces.com)"; #endif #define TR_VERSION "6.0 GOLD" #include #define IP_VERSION 4 /* We can't work with anything else... */ #define CISCO_ICMP 1 /* We check for loss+unreachables = probes */ #ifdef __decc /* DEC C wants strings.h to be called string.h */ #define STRING #define NOINDEX #define NOBZERO #endif #ifdef SOLARIS /* Solaris has UCB stuff gone, and POSIX resolver */ #define SUN_WO_UCB #define POSIX #endif #ifdef SUN_WO_UCB #define STRING #define NOINDEX #include #endif #ifdef _AIX /* Aix has its own set of fd_* macros */ #include #include #endif #ifdef STRING #include #else /* ! STRING */ #include #endif /* STRING */ #include #ifdef NOINDEX #define index(x,y) strchr(x,y) /* Use ansi strchr() if no index() */ #endif /* NOINDEX */ #ifndef bzero #ifdef NOBZERO #define bzero(x,y) memset((void *)x,(int)0,(size_t) y) #define bcopy(x,y,z) memcpy((void *)y, (const void *)x, (size_t) z) #endif /* NOBZERO */ #endif /* bzero*/ #include /* For atof(), etc. */ #include /* For getpid(), etc. */ /* The VMS stuff follows */ #ifdef vms pid_t decc$getpid(void); /* Just don't ask...*/ #define getpid decc$getpid /* Really... don't ask.*/ #define perror socket_perror /* MultiNet wants this */ #ifdef MULTINET_V3 #define errno socket_errno /* MultiNet wants this */ #include "multinet_root:[multinet.include]errno.h" #else /* MULTINET_V4 */ #define MULTINET_V4 #include #ifdef errno #undef errno #include "multinet_root:[multinet.include]errno.h" #define errno socket_errno /* Multinet 4.1 */ #endif /* errno defined */ #endif /* MULTINET_V3 */ #define write socket_write /* MultiNet wants this */ #define read socket_read /* MultiNet wants this */ #define close socket_close /* MultiNet wants this */ #include #ifdef __alpha #define BYTE_ORDER 1234 /* The include files for Alpha are bad. */ #define LITTLE_ENDIAN 1234 /* They incorrectly swap ip_v and ip_hl */ #define BIG_ENDIAN 4321 /* Which makes packet_ok fail. New diag */ #endif /* __alpha */ /* Info says: packet version not 4: 5 */ #ifdef VMS_CLD /* use separate qualifers instead of options */ #include "clis.h" #else /* No CLD */ int fixargs(int *, char **, char **); #endif /* VMS_CLD */ #else /* not VMS */ #include #endif /* vms */ #include #include #include #include #ifndef vms /* Not VMS */ #ifdef POSIX /* Posix */ #define BIND_RES_POSIX3 #include #ifdef res_mkquery /* __res_mkquery() */ #undef res_mkquery #endif /* endif */ #ifdef res_send #undef res_send #endif #else /* POSIX */ /* else ! Posix */ #include #endif /* POSIX */ /* Endif Posix */ #else /* vms */ /* else VMS */ #ifdef MULTINET_V4 /* they didn't put the prototypes in the file */ #include int res_send(unsigned char *, int, unsigned char *, int); int res_mkquery(int op, const char *dname, int class, int type, const char *data, int datalen, void *, u_char *buf, int buflen); int gettimeofday(struct timeval *, void *); #endif /* MULTINET_V4 */ #endif /* __vms */ /* Endif VMS */ #ifdef __linux__ /* Wrapping this may be excessive */ #define __FAVOR_BSD #endif #ifndef MAX_DATALEN #define MAX_DATALEN 32000 /* Maximum size of MTU discovery packet length*/ #endif #include #include #include #include #include #ifndef __linux__ #include #else /* __linux__ */ #include #include #endif /* __linux__ */ #include #include #include #include #include /* After resolv.h for gcc2.7/sun __p redef */ #ifndef NO_PROTOTYPES /* By default, have prototypes */ int send_probe(int, int); int wait_for_reply(int, struct sockaddr_in *, struct timeval *); int packet_ok(u_char *, int, struct sockaddr_in *, int); int tvsub(struct timeval *, struct timeval *); void print_time(float *); void print_from(struct sockaddr_in *); int print(u_char *, int, struct sockaddr_in *); int reduce_mtu(int); int doqd(unsigned char *, int); int dorr(unsigned char *, int, char **); int doclass(unsigned char *, int); int dordata(unsigned char *, int, int, int, char *, char **); int dottl(unsigned char *,int); int doname(unsigned char *, int, char *); int dotype(unsigned char *, int); void AbortIfNull (char *); void print_ttl(int); void print_packet(struct ip *, int); #endif /* NO_PROTOTYPES */ #define MAXPACKET 65535 /* max ip packet size */ #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif #define SIZEOFstructip sizeof(struct ip) #ifndef FD_SET #define NFDBITS (8*sizeof(fd_set)) #define FD_SETSIZE NFDBITS #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) #endif #define Fprintf (void)fprintf #define Sprintf (void)sprintf #define Printf (void)printf #define NOERR(val,msg) {if (((int)(val)) < 0) {perror(msg);exit(1);}} #ifndef NO_SOA_RECORD #define NO_SOA_RECORD "no SOA record" #endif /* For some reason, IP_HDRINCL and LSRR don't interact well on SGI; * so turn it off: */ #ifdef sgi #undef IP_HDRINCL #endif #ifndef vms extern int errno; #endif extern char *inet_ntoa(); extern u_long inet_addr(); #ifndef ULTRIX43 char *index(const char *string, int character); #endif void halt(); /* signal handler */ /* * format of a (udp) probe packet. */ struct opacket { struct ip ip; struct udphdr udp; u_char seq; /* sequence number of this packet */ u_char ttl; /* ttl packet left with */ struct timeval tv; /* time packet left */ }; #ifdef SPRAY /* * format of a spray data cell. */ #define SPRAYMAX 256 /* We'll only do up to 256 TTLs at once */ struct { u_long dport; /* check for matching dport */ u_char ttl; /* ttl we sent it to */ u_char type; /* icmp response type */ struct timeval out; /* time packet left */ struct timeval rtn; /* time packet arrived */ struct sockaddr_in from; /* whom from */ } spray[SPRAYMAX]; #define ASNMAX 256 struct { char name[256]; char asn[100]; int addr; } asns[ASNMAX]; #define OWNERMAX 256 struct { char name[256]; char address[256]; int addr; } owners[OWNERMAX]; int current_asn = 0; int current_owner = 0; int spray_rtn[SPRAYMAX]; /* See which TTLs have responded */ int spray_target; /* See which TTL the host responds on */ int spray_max; /* See which is the highest TTL we've seen */ int spray_min; /* See smallest host-returned TTL */ int spray_total; /* total of responses seen */ int spray_mode =0; /* By default, turned off */ #endif /* SPRAY */ u_char packet[512]; /* last inbound (icmp) packet */ struct opacket *outpacket; /* last output packet */ char *inetname(); u_char optlist[MAX_IPOPTLEN]; /* IP options list */ int _optlen; struct icmp *icp; /* Pointer to ICMP header in packet */ int s; /* receive (icmp) socket file descriptor */ int sndsock; /* send (udp) socket file descriptor */ #if defined(FREEBSD) || defined(__linux__) struct timezone tz; #else unsigned long tz; /* leftover */ #endif struct sockaddr whereto; /* Who to try to reach */ struct sockaddr_in addr_last; /* last printed address */ int datalen; /* How much data */ char *source = 0; char *hostname; char hnamebuf[MAXHOSTNAMELEN]; int nprobes = 3; int min_ttl = 1; int max_ttl = 30; u_short ident; u_short port = 32768+666; /* start udp dest port # for probe packets */ u_short sport = 1000; /* source port ... */ int options; /* socket options */ int verbose; int mtudisc=0; /* do MTU discovery in path */ int pingmode=0; /* replacing ping functionality? */ #ifndef vms float waittime = 3.0; /* time to wait for response (in seconds) */ #else /* vms */ double waittime = 3.0; #endif int nflag; /* print addresses numerically */ #define TERM_SIZE 32 /* Size of line terminator... */ char terminator[TERM_SIZE]; /* Line terminator... */ int haltf=0; /* signal happened */ int ppdelay=1; /* we normally want per-packet delay */ int pploss=0; /* we normally don't want packet loss */ int lost; /* how many packets did we not get back */ double throughput; /* percentage packets not lost */ int consecutive=0; /* the number of consecutive lost packets */ int automagic=0; /* automatically quit after 10 lost packets? */ int hurry_mode=0; /* only do one on successful ttls */ int utimers=0; /* Print timings in microseconds */ int dns_owner_lookup=0; /* Look up owner email in DNS */ int as_lookup=0; /* Look up AS path in routing registries */ int got_there; int unreachable; int mtu, new_mtu = 0; /* * Lookup origin of the net in radb. */ char *lookup_as(in) struct in_addr in; { static char query[100]; static unsigned char *addr_ptr; static char *sp; char *get_origin(); addr_ptr = (unsigned char *) (&in.s_addr); #ifdef FORCE_NATURAL_MASK if (addr_ptr[0] >= 192) { sprintf (query, "%d.%d.%d.0",addr_ptr[0],addr_ptr[1],addr_ptr[2]); } else if (addr_ptr[0] >= 128) { sprintf (query, "%d.%d.0.0",addr_ptr[0],addr_ptr[1]); } else { sprintf (query, "%d.0.0.0",addr_ptr[0]); } #else sprintf (query,"%d.%d.%d.%d",addr_ptr[0],addr_ptr[1],addr_ptr[2],addr_ptr[3]); #endif /* FORCE_NATURAL_MASK */ return(get_origin(query)); } /* * get_origin - Return origin (ASnnnn) given a network designation * * char *get_origin(char *net_designation) * * Returns: 0 - Error occurred, unable to get origin * !0 Pointer to origin string * * Define STANDALONE to use this as a client. Also define EXAMPLE_NET for * an example for the truly clueless... * * 20-May-1995 Ehud Gavron gavron@aces.com */ /* The following are used to determine which service at which host to connect to. A getenv() of the following elements occurs at run-time, which may override these values. */ #define RA_SERVER "whois.ra.net" #define RA_SERVICE "whois" /* The following determines what fields will be returned for the -A value (/AS_LOOKUP for VMS). This is the "origin" of the route entry in the RADB. */ #define DATA_DELIMITER "origin:" /* Since now the RADB has multiple route objects, we will list only the origin of the most specific one. To do so we actually have to parse the route lines and look for the most specific route. To do so we parse: net.net.net.net/prefix and use the most specific (largest) prefix. The following determine how we get this. */ #define ROUTE_DELIMITER "route:" #define PREFIX_DELIMITER "/" #ifdef STANDALONE #ifdef __vms #include "multinet_root:[multinet.include.sys]types.h" #include "multinet_root:[multinet.include.sys]socket.h" #include "multinet_root:[multinet.include.netinet]in.h" #include #include "multinet_root:[multinet.include]netdb.h" #define perror socket_perror #define write socket_write #define read socket_read #define close socket_close #else /* not VMS */ #include #include #include #include #include #endif /* VMS */ #endif /* STANDALONE */ #ifndef boolean #define boolean int #endif #ifndef TRUE #define TRUE (1==1) #endif #ifndef FALSE #define FALSE (!(TRUE)) #endif #define MAXREPLYLEN 8192 char *get_origin(name, addr) char *name; { char *i,*j,*k; char tmp[100],tmp2[100],tmp3[100]; /* store string delimiters */ char tmp4[100]; /* here's where we store the AS */ static char origin[100]; /* the returned route origin */ char *rp; /* pointer to route: line */ char *pp; /* pointer to /prefix part of route */ int prefix; /* prefix off this line (decimal) */ int best_prefix; /* best prefix thus far */ int s, n, count; int z = 0; char buf[256]; boolean done; static char reply[MAXREPLYLEN]; struct sockaddr_in sin; struct hostent *hp; struct servent *sp; char *getenv(); if (current_asn > 0) { while (z <= current_asn) { z++; // fprintf(stderr,"%s <> %s || %d.%d.%d.%d <> %d.%d.%d.%d\r\n\n",name,asns[z].name, // (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff, // (asns[z].addr >> 24) & 0xff, (asns[z].addr >> 16) & 0xff, (asns[z].addr >> 8) & 0xff, asns[z].addr & 0xff); if (!strcmp(name,asns[z].name) || addr == asns[z].addr) { return asns[z].asn; } } } /* * Get the IP address of the host which serves the routing arbiter * database. We use RA_SERVER. On the offchance that someone wants * to query another database, we check for the environment variable * RA_SERVER to have been set. */ if ((i = getenv("RA_SERVER")) == 0) { strcpy(tmp,RA_SERVER); } else { strncpy(tmp,i,sizeof(tmp)); tmp[(sizeof(tmp))-1] = '\0'; /* strncpy may not null term */ } hp = gethostbyname(tmp); if (hp == NULL) { Fprintf(stderr, "get_origin: localhost unknown%s",terminator); return(0); } /* * Create an IP-family socket on which to make the connection */ s = socket(hp->h_addrtype, SOCK_STREAM, 0); if (s < 0) { perror("get_origin: socket"); return(0); } /* * Get the TCP port number of the "whois" server. * Again if this needs to be updated, the environment variable * RA_SERVICE should be set. */ if ((i = getenv("RA_SERVICE")) == 0) { strcpy(tmp,RA_SERVICE); } else { strncpy(tmp,i,sizeof(tmp)); tmp[(sizeof(tmp))-1] = '\0'; /* strncpy may not null term */ } sp = getservbyname(tmp,"tcp"); if (sp == NULL) { Fprintf(stderr, "get_origin: getservbyname: unknown service%s",terminator); return(0); } /* * Create a "sockaddr_in" structure which describes the remote * IP address we want to connect to (from gethostbyname()) and * the remote TCP port number (from getservbyname()). */ sin.sin_family = hp->h_addrtype; bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); sin.sin_port = sp->s_port; /* * Connect to that address... */ if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) { perror("get_origin: connect"); return(0); } /* * Now send the request out to the server... */ done = FALSE; sprintf(buf,"%s\r\n",name); write(s, buf, strlen(buf)); /* * Now get the entire answer in one long buffer... */ count = 0; while ((n = read(s, buf, sizeof(buf))) > 0) { strcpy((char *)&reply[count],(char *)buf); count += n; } if (n < 0) { perror("get_origin: read"); return(0); } reply[count] = '\0'; /* Terminate it - thanks Joey! */ /* * So now we have a large string, somewhere in which we can * find origin:*AS%%%%%%. We parse this into AS%%%%%. */ if ((i = getenv("DATA_DELIMITER")) == 0) { strcpy(tmp,DATA_DELIMITER); } else { strncpy(tmp,i,sizeof(tmp)); tmp[(sizeof(tmp))-1] = '\0'; /* strncpy may not null term */ } /* TMP2 will have the route delimiter... */ if ((i = getenv("ROUTE_DELIMITER")) == 0) { strcpy(tmp2,ROUTE_DELIMITER); } else { strncpy(tmp,i,sizeof(tmp)); tmp[(sizeof(tmp))-1] = '\0'; /* strncpy may not null term */ } if ((i = getenv("PREFIX_DELIMITER")) == 0) { strcpy(tmp3,PREFIX_DELIMITER); } else { strncpy(tmp3,i,sizeof(tmp3)); tmp3[(sizeof(tmp3))-1] = '\0'; /* strncpy may not null term */ } /* * The next while statement was put in because of SPRINTLINK's ingeneous * Reasonable Default announcement project. They registered nets in the * RADB of the ilk of 0.0.0.0/1, 128.0.0.0/1, 192..../2, etc... just so * that ANS wouldn't be such a pain in the butt. * * For us this means instead of taking the first origin...we take the best... */ /* * Initialize it so far as we've seen no prefixes, and are still looking * for route entries... */ best_prefix = 0; /* 0 bits is not very specific */ done = FALSE; /* not done finding route: entries */ rp = (char *)reply; /* initialize main pointer to buffer */ origin[0]='\0'; /* initialize returned string */ reply[MAXREPLYLEN-1]='\0'; rp = (char *)strstr(rp,tmp2); /* Find route: in the string */ while (rp != 0) { /* If there is such a thing... */ /* find it again later */ pp = (char *)strstr(rp,tmp3); /* Find / in the route entry */ if (pp == 0) { /* No prefix... */ prefix = 0; /* So we bias it out of here */ } else { prefix = atoi(pp+1); /* convert to decimal*/ } if (prefix >= best_prefix) { /* it's equal to or better */ i = (char *)strstr(pp,tmp); /* find origin: delimiter */ if (i != 0) { /* it's nice if there is one */ i += strlen(DATA_DELIMITER); /* skip delimiter... */ i++; /* and the colon... */ while (*i == ' ') i++; /* skip spaces */ /* i now points to start of origin AS string */ j = i; /* terminate... */ while (*j >= '0') j++; if (prefix > best_prefix) { strcpy(origin,"/"); /* put a slash in */ best_prefix = prefix; /* update best */ } else { strcat(origin,"/"); /* put a mutiple as separator*/ } strncpy(tmp4,i,(j-i)); /* copy new origin */ tmp4[j-i] = '\0'; /* null terminate it */ if (!(strstr(origin,tmp4))) { /* if it's not a dup */ strncat(origin,i,(j-i)); /* stick it in */ } else { if (prefix == best_prefix) /* Otherwise remove slash */ origin[strlen(origin)-1] = '\0'; } /* end if not a dup */ } /* end if origin found */ } /* endif prefix > best_prefix */ rp = (char *)strstr(rp+1,tmp2); /* Find route: in the string */ } /* end while */ /* * Go home... */ close(s); if (best_prefix != 0) { /* did we get anything? */ current_asn++; strcpy(asns[current_asn].asn,(char *)&origin[1]); strcpy(asns[current_asn].name,name); asns[current_asn].addr = addr; return((char *)&origin[1]); /* strip off leading slash */ } else { current_asn++; asns[current_asn].asn[0]='\0'; strcpy(asns[current_asn].name,name); asns[current_asn].addr = addr; return(0); } } short getshort(ptr) char *ptr; { union { short retval; char ch[2]; } foo; foo.ch[0] = (*ptr & 0xff); foo.ch[1] = (*(ptr+1) & 0xff); return (foo.retval); } char *doresolve (name) char *name; { int query=QUERY; int qtype=T_SOA; int qclass=C_IN; unsigned char buf[256]; char *ans; int blen, alen, got; int anssiz, i; short shrt; HEADER *h; char *contact_ptr; int ptr; anssiz = 512; ans = (char *)malloc(anssiz); if (!ans) { return(0); } blen = res_mkquery(query,name,qclass,qtype,NULL,0,NULL,(u_char *)buf,sizeof(buf)); if (blen < 0) { return (0); } alen = res_send((unsigned char *)buf,blen,(unsigned char *)ans,anssiz); if (alen == -1) { return (0); } if (alen < 12) { return (0); } h = (HEADER *)ans; h->id = ntohs(h->id); h->qdcount = ntohs(h->qdcount); h->ancount = ntohs(h->ancount); h->nscount = ntohs(h->nscount); h->arcount = ntohs(h->arcount); if (h->ancount == 0) return(0); ptr = 12; /* point at first question field */ for (i=0; i< (int)h->qdcount && ptrancount && ptr 0) { while (z <= current_owner) { z++; if (!strcmp(name,owners[z].name) || addr == owners[z].addr) { return owners[z].address; } } } addr_ptr = (unsigned char *) (&in.s_addr); /* Try /24 */ sprintf (dns_query, "%d.%d.%d.in-addr.arpa", addr_ptr[2], addr_ptr[1], addr_ptr[0]); if (!(owner = doresolve(dns_query))) { /* Failed, try /16 */ sprintf (dns_query, "%d.%d.in-addr.arpa", addr_ptr[1], addr_ptr[0]); if (!(owner = doresolve(dns_query))) { /* Failed. If eligible try /8 */ if (addr_ptr[0] < 128) { sprintf (dns_query, "%d.in-addr.arpa", addr_ptr[0]); owner = doresolve(dns_query); } /* tried /8 for A's */ } /* tried /16 */ } /* tried /24 */ /* reformat slightly */ if (owner == NULL) { owner = NO_SOA_RECORD; } else { dot_ptr = (char *)strchr (owner, (int)'.'); if (dot_ptr != NULL) *dot_ptr = '@'; if (strlen(owner) > 0) { dot_ptr=owner + strlen (owner) - 1; while (*dot_ptr == ' ' || *dot_ptr == '.' ) { *dot_ptr = 0; dot_ptr--; } } } current_owner++; strcpy(owners[current_owner].address,owner); strcpy(owners[current_owner].name,name); owners[current_owner].addr = addr; return (owner); }