#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/socket.h>

#include "as.h"

#ifdef sun
#include <strings.h>
#else
#include <string.h>
#endif

#ifndef boolean
#define boolean int
#endif

#ifndef TRUE
#define TRUE (1==1)
#endif

#ifndef FALSE
#define FALSE (!(TRUE))
#endif
#define MAXREPLYLEN 8192

/* marks the end of a reply (in case of whois.ripe.net another
   welcome messages may follow ... shoudl do substr search sigh) */

#define REPLY_DELIMITER "\n\n\n"


#define DEL_LENGTH	strlen(REPLY_DELIMITER)

#define DATA_DELIMITER "origin:"
#define ROUTE_DELIMITER "route:"
#define ROUTE_DELIMITER_IP6 "route6:"
#define PREFIX_DELIMITER "/"

#define MAX_RECONNECT 50

int reconnect_count = 0;

void RRopen(char *server, char* service) {

	/*
 	 * Setup connection to the specified routing registry. 
	 * We assume a RIPE Whois like server, featuring a 
	 * 'keep alive' option so we don't have to go through the
	 * expensive TCP connect and setup phases for each request. 
	 * Can be overridden by enviroment variable.  [RW 20020813]
	 */

	char *cp;
	struct hostent *hp;
	struct servent *sp;
	char *getenv();

	/* Wipe structure, we may be called more than once.. */
	bzero(&RRsockaddr,sizeof(RRsockaddr));

	if ((cp = getenv("IRR_SERVER")) == 0) {
		cp = server;
	} 

	hp = gethostbyname(cp);
	if (hp == NULL) {
		fprintf(stderr, "RRconnect: host %s unknown\n", cp);
		exit(1);
	}

	/*
	 *  Create an IP-family socket on which to make the connection
	 */

	RRsock = socket(hp->h_addrtype, SOCK_STREAM, 0);
	if (RRsock < 0) {
		perror("RRconnect: socket");
		exit(1);
	}

	/*
	 *  Get the TCP port number of the IRR server.
	 *  Again if this needs to be updated, the environment variable
	 *  IRR_SERVICE should be set.
	 */

        if ((cp = getenv("IRR_SERVICE")) == 0) {
        	cp = service;
        } 

	sp = getservbyname(cp,"tcp");
	if (sp == NULL) {
		fprintf(stderr, "RRconnect: getservbyname: %s: unknown service\n", cp);
		exit(1);
	}

	/*
	 *  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()).
	 */

	RRsockaddr.sin_family = hp->h_addrtype;
	bcopy(hp->h_addr, (caddr_t) &RRsockaddr.sin_addr, hp->h_length);
	RRsockaddr.sin_port = sp->s_port;
}

void RRconnect() {

	int n, count;
	char buf[256];

	static char reply[MAXREPLYLEN];

	/*
	 *  Connect to the address
	 */

retry_connect:

	if (connect(RRsock, (struct sockaddr *)&RRsockaddr, sizeof (RRsockaddr)) < 0) {
		perror("RRconnect: connect");
	        reconnect_count++;
	
	        if (reconnect_count > MAX_RECONNECT) {
	    	    /* serious trouble */
				fprintf(stderr, "maximum number of reconnects reached, bailing out... \n");
	    	    exit(1);
	        }
	        goto retry_connect;
	}
	/*
	 *  Read the welcome message (terminated by empty line)
	 */

	count=0;
	do {
	    if ((n = read(RRsock, buf, sizeof(buf))) > 0) {
	        strncpy((char *)&reply[count],(char *)buf,n);
	        count += n;
	    }
	} while ((strncmp (&reply[count - 2], "\n\n", 2) != 0) && (n > 0));

#ifdef DEBUG
	reply[count] = '\0';
	fprintf(stderr, "RRconnect: <greeting>%s</greeting>\n", reply);
#endif

	/*
	 *  Send keep alive request to the server...
	 */

	write(RRsock, "-k\r\n", 4);

	count=0;

#ifdef DEBUG
	reply[count] = '\0';
	fprintf(stderr, "RRconnect: <reply>%s</reply>\n", reply);
#endif

}

/*
-------------------------------------------------------------------------------
Subroutine Header
Purpose           :     assign origin AS to IP number 
input             :     IP (character strign), flag to indicate IPv6 or IPv4
returns           :     origin AS or NULL if not found
Comments          :     This routine is a modified version of the get_origin
			function from traceroute-nanog-6.1.1 package
-------------------------------------------------------------------------------
*/

char *get_origin(char *net, int ip6flag) {

	char *i, *j;
	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 n, count;
	char buf[MAXREPLYLEN];
	boolean done;
	static char reply[MAXREPLYLEN];
	char *getenv();

	done = FALSE;

retry_write:
	sprintf(buf,"-T route -a %s\n", net);
	n = write(RRsock, buf, strlen(buf));

	if (n < 0) {
	    perror("get_origin: write");
	    fprintf(stderr, "attempting reconnect ... \n");
	    usleep(0.5);
		/* Completely reinitialize */
	    close(RRsock);
	    RRopen(RR_SERVER, RR_SERVICE);
	    RRconnect();
	    reconnect_count++;
	
	    if (reconnect_count > MAX_RECONNECT) {
		/* serious trouble */
	    	exit(1);
	    }
	    goto retry_write;
	}
	else if (n != strlen(buf)) {
		fprintf(stderr, "get_origin: write: wrote %d of %d bytes\n",			  n, strlen(buf));
	    fprintf(stderr, "attempting reconnect ... \n");
	    usleep(0.5);
	    /* Completely reinitialize */
	    close(RRsock)            ;
	    RRopen(RR_SERVER, RR_SERVICE);
	    RRconnect();
	    reconnect_count++;
	
	    if (reconnect_count > MAX_RECONNECT) {
		/* serious trouble */
			fprintf(stderr, "maximum number of reconnects reached, bailing out... \n");
	    	exit(1);
	    }
	    goto retry_write;
	}

#ifdef DEBUG
	fprintf(stderr, "<request>%s</request>\n\n",buf);
#endif

	/*
	 * Now get the entire answer in one long buffer...
	 */
	count = 0;
#ifdef DEBUG
	fprintf(stderr,"doing read loop:\n");
#endif
	do {
	    if ((n = read(RRsock, buf, sizeof(buf))) > 0) {
	        strncpy((char *)&reply[count],(char *)buf,n);
	        count += n;
#ifdef DEBUG
{	       int jjj;
		buf[n+3]='\0';
		fprintf(stderr,"read %d bytes\n>>%s<<\n",n,buf);
		fprintf(stderr,"last %d bytes\n===\n", DEL_LENGTH);
		for (jjj=count-DEL_LENGTH; jjj<=count; jjj++) {
			fprintf(stderr, "%c", reply[jjj]);
		}
		fprintf(stderr,"===\n");
}
#endif
	    }
	} while ((strncmp (&reply[count - DEL_LENGTH], REPLY_DELIMITER, DEL_LENGTH) != 0) && (n > 0));

/* in RIPE whois server keep alive mode, reply ends with greeting
   have to search for DELIMITER in the whole reply

	} while ((strstr (reply, REPLY_DELIMITER) != NULL) && (n > 0));
 */
#ifdef DEBUG
fprintf(stderr,"done.\n");
#endif

	if (count > MAXREPLYLEN) {
            fprintf(stderr, "errorr: buffer length exceeded: available %d , read %d\n", count, MAXREPLYLEN);
	    exit(1);
	}


	if (n < 0) {
	    perror("get_origin: read");
	    return(0);
	}

	reply[count] = '\0';	/* Terminate reply */

#ifdef DEBUG
	fprintf(stderr, "reply: %s\n",reply);
#endif

	/* 
	 * So now we have a large string, somewhere in which we can
	 * find  origin:*AS%%%%%%<lf>.  We parse this into AS%%%%%.
	 */
	
	strcpy(tmp,DATA_DELIMITER);

	/* TMP2 will have the route delimiter... */

	if (ip6flag) {
	   strcpy(tmp2,ROUTE_DELIMITER_IP6);
	}
	else {
	   strcpy(tmp2,ROUTE_DELIMITER);
	}

	strcpy(tmp3,PREFIX_DELIMITER);
	
/*
 * Find the longest matching (=best) route in the returned objects
 */
	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 */

		 /* move 2 more forward to get the number itself [RW] */
		 i += 2;

	         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 */

		    /* search for changed fields, find latest, compare with
		       previous date, if newer replace, if equal stick it in */

	            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... 
	 */
	if (best_prefix != 0) {			/* did we get anything? */
	   return((char *)&origin[1]);		/* strip off leading slash */
	} else {
	   return(0);
	}	   
}
