#include #ifdef sun #include #else #include #endif #include #include #include #include "as.h" #include "read_line.h" #include "common.h" #include #include #include /* ------------------------------------------------------------------------------- Purpose : Read and parse next line from traceroute output file Input : buffer holding the input line, Hash table of previous IP-AS num matches Output : src pointer to Starting point (binary IP num) : dest pointer to End point (binary format IP) : time pointer to Time when the vector was determined : npoint pointer to Number of points along the way. : ipvec routing vector (char string with integer IPs) : aspath The AS numbers corresponding to IPvec : asnums (upated) hash table Comments : the get_origin() routine can return more than one AS matching a single prefix, either due to old records hanging in around in routing registry or some form of multihomedness. Thus the asnums hash indexed by ipnums is filled with and returns character string of one or more ASnum sperated by / : Both for the aspath and the ip vector the calling porgram ia assumed to have taken care of memory allocation. NOTE : The input buffer will be modified in the process of decoding; calling routines MUST make a copy if they need the contents further on. Returns : 0 if the line was successfully read, 1 if a line could be read but didn't contain valid data. 2 if nothing could be read. -1 if the line was read succesfully but last IP != dst static char const rcsid[] = "$Id: read_line.c,v 1.8 2004/03/10 18:04:33 wilhelm Exp $"; */ int read_line (char *buf, unsigned int *src, unsigned int *dest, int* time, int *npoints, char *ipvec, char *aspath, GHashTable* asnums) { char **ap, *arg[MAXWORDS]; int argc; unsigned int ipnum; char *point,*current; int i; point = buf; if (point == NULL) return 2; if (buf[strlen(buf)-1] == '\n') { /* chop off trailing newline char */ buf[strlen(buf)-1] = '\0'; } argc = 0; #if defined(USE_STRTOK) /* POSIX compliant */ /* Split line into elements */ ap = arg; *ap = strtok (point, " \t"); while (*ap != NULL) { if (**ap != '\0') { ++ap; ++argc; } *ap = strtok (NULL, " \t"); } #else /* BSD specific */ /* Split line into elements */ for (ap = arg; (*ap = strsep (&point," \t")) != NULL ;) { if (**ap != '\0') { ++ap; ++argc; } } #endif /* Check if it starts with "RVEC" */ if ((arg[0] == NULL) || (strcmp(arg[0], "RVEC") != 0)) { #ifdef DEBUG printf ("Line did not start with RVEC\n"); #endif return 1; } if (argc < 7) { /* Not at least 5 data elements (src, dst, time, #points endpoint) */ #ifdef DEBUG printf ("Not at least 5 data items\n"); #endif return 1; } if (atoi(arg[1]) != atoi(arg[5]) + 4) { /* Not at least 4 data elements (src, dest, time, #points) */ #ifdef DEBUG printf ("Number of elements mismatch\n"); #endif return 1; } if (argc != atoi(arg[1]) + 2) { /* incomplete line */ #ifdef DEBUG printf ("Number of elements mismatch, incomplete line\n"); #endif return 1; } /* Convert the elementes on the line to something interesting */ #ifdef DEBUG printf ("Converting strings...\n"); #endif *src = rv_iptoint(arg[2]); *dest = rv_iptoint(arg[3]); if (*src == 0 || *dest == 0) { /* error decoding source or destination, give up on this line */ #ifdef DEBUG printf ("invalid source/destination IP address encountered; %s", "giving up on this line\n"); #endif return 1; } *time = atoi (arg[4]); *npoints = atoi (arg[5]); /* If there are more than 30 hops, traceroute mysteriously failed, ignore the entry */ if (*npoints > 30) { #ifdef DEBUG printf ("More than 30 hops, entry ignored!\n"); #endif return 1; } /* line seems ok, add IPnums to route vector, create aspath */ ipnum=0; ipvec[0] = '\0'; /* start with empty vector */ aspath[0] = '\0'; /* ........... and path */ for (i=0; i < (*npoints); i++) { char ips[MAX_IP_SIZE+1]; /* lookup AS num */ current = match_ip_as (asnums, arg[6+i], 0); /* add integer ip num to vector note that rv_iptoint will *change* the input string so this comes _after_ asnum lookup */ ipnum = rv_iptoint(arg[6+i]); strcat(aspath, current); if (i != (*npoints)-1) { strcat(aspath, " "); sprintf(ips, "%u ", ipnum); } else { sprintf(ips, "%u", ipnum); } strcat(ipvec, ips); } /* Check if the traceroute reached the target destination */ if (ipnum == *dest) { return(0); } else { return(-1); } } /* ------------------------------------------------------------------------------- Purpose : IPv6 counterpart to read_line() Input : buffer holding the input line, Output : src pointer to IPv6 address string (source Testbox) : dest pointer to IPv6 address string (destination TB) : time pointer to Time when the vector was determined : npoint pointer to Number of points along the way. : ipvec routing vector (char string with ASCII IPs) Comments : For the ip vector the calling porgram is assumed to have taken care of memory allocation. NOTE : The input buffer will be modified in the process of decoding; calling routines MUST make a copy if they need the contents further on. Returns : 0 if the line was successfully read, 1 if a line could be read but didn't contain valid data. 2 if nothing could be read. -1 if the line was read succesfully but last IP != dst */ int read_line_ip6 (char *buf, char **src, char **dest, int* time, int *npoints, char *ipvec, char *aspath, GHashTable* asnums) { char **ap, *arg[MAXWORDS]; int argc; char *point,*current; int i; char ip6addr[INET6_ADDRSTRLEN]; point = buf; if (point == NULL) return 2; if (buf[strlen(buf)-1] == '\n') { /* chop off trailing newline char */ buf[strlen(buf)-1] = '\0'; } argc = 0; #if defined(USE_STRTOK) /* POSIX compliant */ /* Split line into elements */ ap = arg; *ap = strtok (point, " \t"); while (*ap != NULL) { if (**ap != '\0') { ++ap; ++argc; } *ap = strtok (NULL, " \t"); } #else /* BSD specific */ /* Split line into elements */ for (ap = arg; (*ap = strsep (&point," \t")) != NULL ;) { if (**ap != '\0') { ++ap; ++argc; } } #endif /* Check if it starts with "RVEC6" */ if ((arg[0] == NULL) || (strcmp(arg[0], "RVEC6") != 0)) { #ifdef DEBUG printf ("Line did not start with RVEC6\n"); #endif return 1; } if (argc < 7) { /* Not at least 5 data elements (src, dst, time, #points endpoint) */ #ifdef DEBUG printf ("Not at least 5 data items\n"); #endif return 1; } if (atoi(arg[1]) != atoi(arg[5]) + 4) { /* Not at least 4 data elements (src, dest, time, #points) */ #ifdef DEBUG printf ("Number of elements mismatch\n"); #endif return 1; } if (argc != atoi(arg[1]) + 2) { /* incomplete line */ #ifdef DEBUG printf ("Number of elements mismatch, incomplete line\n"); #endif return 1; } /* Convert the elementes on the line to something interesting */ #ifdef DEBUG printf ("Storing strings...\n"); #endif *src = arg[2]; *dest = arg[3]; if ( ( (strcmp(arg[2],"0::0") != 0) && (inet_pton(AF_INET6,arg[2],ip6addr) < 1) ) || ( (strcmp(arg[3],"0::0") != 0) && (inet_pton(AF_INET6,arg[3],ip6addr) < 1) ) ) { /* error decoding source or destination, give up on this line */ #ifdef DEBUG printf ("invalid source/destination IPv6 address encountered; %s", "giving up on this line\n"); #endif return 1; } *time = atoi (arg[4]); *npoints = atoi (arg[5]); /* If there are more than 30 hops, traceroute mysteriously failed, ignore the entry */ if (*npoints > 30) { #ifdef DEBUG printf ("More than 30 hops, entry ignored!\n"); #endif return 1; } /* line seems ok, add IPnums to route vector, create aspath */ ipvec[0] = '\0'; /* start with empty vector */ aspath[0] = '\0'; /* ........... and path */ for (i=0; i < (*npoints); i++) { if(inet_pton(AF_INET6,arg[6+i],ip6addr)) { char ips[MAX_IP6_SIZE+2]; current = match_ip_as (asnums, arg[6+i], 1); strcat(aspath, current); if (i != (*npoints)-1) { strcat(aspath, " "); sprintf(ips, "%s ", arg[6+i]); } else { sprintf(ips, "%s", arg[6+i]); } strcat(ipvec, ips); } else { #ifdef DEBUG printf ("invalid IPv6 hop address encountered; %s", "giving up on this line\n"); #endif return 1; } } /* Check if the traceroute reached the target destination */ i--; if (strcmp(arg[6+i], *dest) == 0) { return(0); } else { return(-1); } } /* ------------------------------------------------------------------------------- Subroutine Header Purpose : find matching ASnum(s) for specific IPs Input : hash table with results from previous lookups IP address (ascii format) Returns : matching ASnums (character string) or NULL if no match Comments : When more than one AS is found to originate the IP, all matching ASnums are returned , seperated by a / Note : GHashTable only stores pointers, the application must take care of memory allocation, so we malloc() here ------------------------------------------------------------------------------- */ char *match_ip_as (GHashTable* asnums, char *ipstring, int ip6flag) { char *AS; char *value; int *key; int length; char *ipcopy; ipcopy = malloc(strlen(ipstring)+1); /* must copy, rv_iptoint will truncate and the v6 hash needs a stable key */ strcpy(ipcopy, ipstring); if (!ip6flag) { /* IPv4 hash key is the 32 bit IP address */ key = (int *) malloc(sizeof(int)); *key = rv_iptoint (ipcopy); AS = g_hash_table_lookup(asnums, key); free(ipcopy); /* v4 no longer needs it */ } else { /* IPv4 hash key is the ASCII string representing IPv6 addr */ AS = g_hash_table_lookup(asnums, ipcopy); } if (AS == NULL) { /* search for it in the DB and insert in the hash table */ AS = get_origin(ipstring, ip6flag); if (AS == NULL) { AS = "0"; /* not a real AS -> no data */ } length = strlen(AS) + 1; value = (char *) malloc(length); strncpy(value, AS, length); /* insert in the hash table */ if (!ip6flag) { g_hash_table_insert (asnums, key, value); } else { g_hash_table_insert (asnums, ipcopy, value); } } return(AS); } /* ------------------------------------------------------------------------------- */ char* rv_inttoip (unsigned int ipno, char* point) { /* ============ Converts an unsigned int ("0x01020304") into a standard IP number (1.2.3.4); Space for the string must have been allocated in the calling routine. */ int byte[4], i; for (i=0 ; i<4 ; i++) { byte[i] = ipno & 0xFF; ipno = ipno / 0x100; } sprintf (point, "%d.%d.%d.%d", byte[3], byte[2], byte[1], byte[0]); return point; } unsigned int rv_iptoint (char * ipstring) { /* ============== Convert IP number (e.g. 1.2.3.4) into an 32 unsigned int ("0x01020304") Input : char * ipstring String containing the ip number Output: unsigned int IP number as a 32 bit unsigned int. Non-numbers in the input string will be converted to FF. */ unsigned int temp; char buffer[10]; char *point= &buffer[0]; int i; point = strtok ( ipstring, "." ); if (point == NULL) { return 0; } if (strcmp(point, "??") == 0) { temp = 0xFF; } else { temp = (int) strtol (point, (char**)NULL, 10); if (temp == 0) { temp = 0xFF; } } for (i=0 ; i<3 ; i++) { point = strtok ( NULL, "." ); if ( (point == NULL) ) { return 0; } else if ((strncmp(point, "??", 2) == 0) ) { /* use strncmp, since last token of a line includes \n char */ temp = temp*0x100 + 0xFF; } else { temp = temp*0x100 + (int) strtol(point, NULL, 10); } } return temp; }