/* ASS
 * Autonomous System Scanner
 * - IGRP
 *
 * FX <fx@phenoelit.de>
 * Phenoelit (http://www.phenoelit.de)
 * (c) 2k
 *
 * $Id: ass_v1.c,v 1.24 2001/12/26 22:41:40 fx Exp fx $
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <rpc/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <math.h>
#include <signal.h>

#include "protocols.h"
#include "packets.h"
#include "build.h"

/* we need a sniffer enigine here */
#include <pcap.h>
#include <net/bpf.h>

/* definitions */
#define IPTTL		0x80
#define RIP_PORT	520
#define HSRP_PORT	1985
#define EIGRP_HELLO_TIME	12

#define IP_BCAST	"255.255.255.255"
#define CAPLENGTH	1542
#define DEST_LENGTH	15

#define BANNER		"ASS [Autonomous System Scanner] $Revision: 1.24 $\n"\
			"\t(c) 2k++ FX <fx@phenoelit.de>\n"\
			"\tPhenoelit (http://www.phenoelit.de)\n"

#define FCHAR_IGRP		'I'
#define FCHAR_EIGRP		'E'
#define FCHAR_EIGRP_RT		'e'
#define FCHAR_IRDP		'R'
#define FCHAR_CDP		'C'
#define FCHAR_RIPv1		'1'
#define FCHAR_RIPv2		'2'
#define FCHAR_HSRP		'H'
#define FCHAR_OSPF		'O'
#define FCHAR_ACTIVE_ALL	"IER12"

/* new result management 
 * ... types */
typedef struct {
    struct in_addr	dest;
    unsigned int	as;
    unsigned long	delay;
    unsigned long	bandw;
    unsigned int	mtu;
    unsigned int	reliability;
    unsigned int	load;
    unsigned int	hopcount;
    void		*next;			// next record
} RES_route_igrp_t;

typedef struct {
    unsigned long	as;
    unsigned short	ios_major;
    unsigned short	ios_minor;
    unsigned short	eigrp_major;
    unsigned short	eigrp_minor;
    void 		*next;
} RES_route_eigrp_t;

typedef struct {
    unsigned long	as;
    unsigned int	type;	/* external or internal */
    struct in_addr	nexthop;
    /* external */
    struct in_addr	origrouter;
    unsigned long	origas;
    unsigned long	externalmetric;
    unsigned short	externallink;
    /* general */
    unsigned long 	delay;
    unsigned long	bandwidth;
    unsigned long	mtu;
    unsigned short	hopcount;
    unsigned short 	reliability;
    unsigned short	load;
    struct in_addr	netmask;
    struct in_addr	dest;
    void		*next;
} RES_route_eigrprt_t;

typedef struct {
    struct in_addr	dest;
    unsigned long	preference;
    void		*next;
} RES_route_irdp_t;

typedef struct {
    struct in_addr	dest;
    unsigned long	metric;
    void		*next;
} RES_route_ripv1_t;

#define RIP2AUTH_NONE	0
#define RIP2AUTH_TEXT	2
#define RIP2AUTH_MD5	3
typedef struct {
    struct in_addr	dest;
    struct in_addr	mask;
    struct in_addr	nexthop;
    unsigned int	routetag;
    unsigned long	metric;
    void		*next;
} RES_route_ripv2_t;

typedef struct {
    struct in_addr	virtip;
    char		auth[9];
    struct ether_addr	vmac;
    unsigned short	version;
    unsigned short	state;
    unsigned short 	hello;
    unsigned short	hold;
    unsigned short	group;
    unsigned short	prio;
    void		*next;
} RES_route_hsrp_t;

typedef struct {
    /* from header */
    struct in_addr	source;
    struct in_addr	area;
    int			authtype;
    char		authdata[9];
    /* from hello */
    struct in_addr	netmask;
    struct in_addr	designated;
    struct in_addr	backup;
    unsigned long	dead;
    unsigned short	prio;
    unsigned int	hello;
    void		*next;
} RES_route_ospf_t;

typedef struct {
    char		*deviceid;
//    struct in_addr	addr;
    char		*portid;
    unsigned long	capas;
    char		*software;
    char		*platform;
    char		*vtpmgmt;
    unsigned int	vlan;
    unsigned short	duplex;
    void		*next;
} RES_cdp_info_t;


#define CAP_IGRP	0x001
#define CAP_IRDP	0x002
#define CAP_EIGRP	0x004
#define CAP_RIPv1	0x008
#define CAP_CDP		0x010
#define CAP_HSRP	0x020
#define CAP_RIPv2	0x040
#define CAP_OSPF	0x080
#define CAP_RIPv2auth	0x100
#define CAP_EIGRP_RT	0x200

typedef struct {
    struct in_addr	addr;
    unsigned int	capa;
    RES_route_igrp_t	*igrp;
    RES_route_irdp_t	*irdp;
    RES_route_ripv1_t	*rip1;
    RES_route_ripv2_t	*rip2;
    unsigned short	rip2auth_type;
    char		rip2pw[17];
    RES_route_eigrp_t	*eigrp;
    RES_route_eigrprt_t	*eigrpr;
    RES_route_hsrp_t	*hsrp;
    RES_route_ospf_t	*ospf;
    RES_cdp_info_t	*cdp;
    void		*next;		// next record
} result_t;


/* config */
struct {
    int			verbose;
    char		*device;

    u_int16_t		as_start,as_stop;
    int			eigrpmc;

    int			spoof_src;
    struct in_addr	src;
    int			set_dest;
    struct in_addr	dest;

    int			prom;
    int			cont;
    int			passive;
    int			cdp_show_software;
    unsigned long	sdelay;
    char		*active_protos;
    char		*inputfile;
} cfg;

/************************************
 * globals */
u_char			*rawpacket;
int			atsock;
pcap_t			*cap;

int			stop_flag=0;

result_t		*anchor;


/************************************
 * prototypes */
void	usage(char *n);

/* IGRP construction */
u_char	*construct_igrp_request(u_int16_t autosys, int *psize);
/* EIGRP construction */
u_char	*construct_eigrp_request(struct in_addr *dd, 
	u_int32_t autosys, int *psize);
/* IRDP construction */
u_char	*construct_irdp_request(int *psize);
/* RIP construction */
u_char	*construct_rip_request(int *psize);
u_char	*construct_rip2_request(int *psize);

/* PCAP */
int     initialize_pcap(void);
void	signaler(int sig);
void	evaluate_packet(u_char *frame,int frame_length);
void 	net_listen(void);

/* result management */
int	add_route(int rtype,struct in_addr *addr,unsigned int as,void *data);
void	print_results(void);
void	clean_results(void);


/* the main function */
int	main(int argc, char **argv) {
    char		option;
    extern char		*optarg;

    unsigned long	tm1;
    int			i;
    /* scanner packet */
    int			plength;
    /* finding former findings */
    result_t		*c;
    RES_route_eigrp_t	*ceigrp;


    memset(&cfg,0,sizeof(cfg));
    cfg.passive=cfg.prom=1;
    while ((option=getopt(argc,argv,"vcpAMsi:a:b:S:D:T:P:r:"))!=EOF) {
	switch (option) {
	    case 'v':	/* verbose */
			cfg.verbose++;
			break;
	    case 'i':	/* local network device */
			cfg.device=smalloc(strlen(optarg)+1);
			strcpy(cfg.device,optarg);
			break;
	    case 'a':	/* autonomous system start*/
			cfg.as_start=atoi(optarg);
			break;
	    case 'b':	/* autonomous system stop */
			cfg.as_stop=atoi(optarg);
			break;
	    case 'S':	/* spoof source */
			if (inet_aton(optarg,&(cfg.src))==0) {
			    fprintf(stderr,
				    "source IP address seems to be wrong\n");
			    return (1);
			}
			cfg.spoof_src++;
			break;
	    case 'D':	/* set destination */
			if (inet_aton(optarg,&(cfg.dest))==0) {
			    fprintf(stderr,
				    "dest. IP address seems to be wrong\n");
			    return (1);
			}
			cfg.set_dest++;
			break;
	    case 'p':	/* promiscous mode */
			cfg.prom=0;
			break;
	    case 'c':	/* don't continue capture */
			cfg.cont++;
			break;
	    case 'T':	/* delay between each packet */
			cfg.sdelay=atol(optarg);
			break;
	    case 'A':	/* not passive */
			cfg.passive=0;
			break;
	    case 'M':	/* EIGRP mutlicast scan */
			cfg.eigrpmc++;
			break;
	    case 's':	/* show CDP software info */
			cfg.cdp_show_software++;
			break;
	    case 'P':	/* selection of protocols */
			cfg.active_protos=smalloc(strlen(optarg)+1);
			strcpy(cfg.active_protos,optarg);
			break;
	    case 'r':	/* input file */
			cfg.inputfile=(char*)smalloc(strlen(optarg)+1);
			strcpy(cfg.inputfile,optarg);
			break;
	    default:	usage(argv[0]);
	}
    }

    if ((!cfg.device)&&(!cfg.inputfile)) usage(argv[0]);
    if (!cfg.set_dest)
	inet_aton(IP_BCAST,&(cfg.dest));

    if (cfg.as_stop==0) 
	cfg.as_stop=65535;
    if (cfg.as_start>cfg.as_stop) {
	fprintf(stderr,"Start has to be smaller then stop ...\n");
	return (1);
    }
    if (cfg.passive) cfg.cont=0;
    if (cfg.active_protos==NULL) {
	cfg.active_protos=smalloc(strlen(FCHAR_ACTIVE_ALL)+1);
	strcpy(cfg.active_protos,FCHAR_ACTIVE_ALL);
    }

    if (cfg.inputfile!=NULL) {
	if (!cfg.passive) 
	    printf("Passive mode implicit when reading from file\n");
	cfg.passive=1; cfg.cont=0;
    }

    if (!cfg.inputfile) {
	/* set up socket ... */
	if ((atsock=init_socket_IP4(cfg.device,1))==(-1)) return(1);
	/* if spoofing is enabled, copy it */
	if (!cfg.spoof_src) {
	    memcpy(&(cfg.src.s_addr), &(packet_ifconfig.ip.s_addr), IP_ADDR_LEN);
	}
    }
    /* set up sniffer */
    if (initialize_pcap()==(-1)) return (1);

    /* signal handling */
    signal(SIGTERM,&signaler);
    //signal(SIGABRT,&signaler);
    signal(SIGINT,&signaler);

    /* my shit */
    printf(BANNER); printf("\tIRPAS build %s\n",BUILD);

    if (!cfg.passive) {

	printf("Scanning\n"); fflush(stdout);

	/* scan for IRDP */
	if (strchr(cfg.active_protos,FCHAR_IRDP)!=NULL) {
	    if (cfg.verbose) printf("+ scanning IRDP ...\n");
	    rawpacket=construct_irdp_request(&plength);
	    sendpack_IP4(atsock,rawpacket,plength);
	    tm1=(unsigned long)time(NULL);
	    while ((!stop_flag)&&(tm1+1>(unsigned long)time(NULL))) 
		net_listen();
	    sendpack_IP4(atsock,rawpacket,plength);
	    free(rawpacket);
	}

	/* scan for RIPv1 */
	if (strchr(cfg.active_protos,FCHAR_RIPv1)!=NULL) {
	    if (cfg.verbose) printf("+ scanning RIPv1 ...\n");
	    rawpacket=construct_rip_request(&plength);
	    sendpack_IP4(atsock,rawpacket,plength);
	    tm1=(unsigned long)time(NULL);
	    while ((!stop_flag)&&(tm1+1>(unsigned long)time(NULL))) 
		net_listen();
	    sendpack_IP4(atsock,rawpacket,plength);
	    free(rawpacket);
	}

	/* scan for RIPv2 */
	if (strchr(cfg.active_protos,FCHAR_RIPv2)!=NULL) {
	    if (cfg.verbose) printf("+ scanning RIPv2 ...\n");
	    rawpacket=construct_rip2_request(&plength);
	    sendpack_IP4(atsock,rawpacket,plength);
	    tm1=(unsigned long)time(NULL);
	    while ((!stop_flag)&&(tm1+1>(unsigned long)time(NULL))) 
		net_listen();
	    sendpack_IP4(atsock,rawpacket,plength);
	    free(rawpacket);
	}

	/* scan IGRP */
	if (strchr(cfg.active_protos,FCHAR_IGRP)!=NULL) {
	    if (cfg.verbose) printf("+ scanning IGRP ...\n");
	    for (i=cfg.as_start;i<=cfg.as_stop;i++) {

		if (cfg.verbose>2) {
		    printf("Scanning %s - AS# %d\n",
			    inet_ntoa(cfg.dest),i);
		}
		
		/* send packet */
		rawpacket=construct_igrp_request(i,&plength);
		sendpack_IP4(atsock,rawpacket,plength);
		free(rawpacket);
		
		net_listen();

		//if (cfg.sdelay) usleep(cfg.sdelay);
		if ((cfg.sdelay)&&((i%cfg.sdelay)==0)) 
		    usleep(10000);
		if (stop_flag) break;
	    }
	}

	/* scan for EIGRP */
	/* IF the destination is set, scan for AS information on this 
	 * router like in IGRP.
	 * IF no destination is set, wait some time for EIGRP HELLOS and 
	 * then scan for their data 
	 */
	if (strchr(cfg.active_protos,FCHAR_EIGRP)!=NULL) {
	    if ((cfg.set_dest)||(cfg.eigrpmc)) {
		struct in_addr	eigrpd;

		if (cfg.set_dest)
		    memcpy(&eigrpd,&(cfg.dest),sizeof(struct in_addr));
		else 
		    inet_aton("224.0.0.10",&eigrpd);

		if (cfg.verbose) printf("+ scanning EIGRP ...\n");
		for (i=cfg.as_start;i<=cfg.as_stop;i++) {

		    if (cfg.verbose>2) {
			printf("Scanning %s - AS# %d\n",
				inet_ntoa(eigrpd),i);
		    }
		    
		    /* send packet */
		    rawpacket=construct_eigrp_request(&eigrpd,
			    (unsigned long)i,&plength);
		    sendpack_IP4(atsock,rawpacket,plength);
		    free(rawpacket);
		    
		    net_listen();

		    //if (cfg.sdelay) usleep(cfg.sdelay);
		    if ((cfg.sdelay)&&((i%cfg.sdelay)==0)) 
			usleep(10000);
		    if (stop_flag) break;
		}
	    } /*end if directed scan */else {
		if (cfg.verbose) 
		    printf("+ wainting for EIGRP HELLOs (%us) ...\n",
			    EIGRP_HELLO_TIME);

		tm1=(unsigned long)time(NULL);
		while ((!stop_flag)&&(tm1+EIGRP_HELLO_TIME>
			    (unsigned long)time(NULL))) 
		    net_listen();

		c=anchor;
		while (c!=NULL) {
		    ceigrp=c->eigrp;
		    while (ceigrp!=NULL) {
			if (cfg.verbose) 
			    printf("++ scanning EIGRP AS %lu on %s\n",
				    ceigrp->as,inet_ntoa(c->addr));

			rawpacket=construct_eigrp_request(
				&(c->addr),ceigrp->as,&plength);
			sendpack_IP4(atsock,rawpacket,plength);
			free(rawpacket);

			tm1=(unsigned long)time(NULL);
			while ((!stop_flag)&&(tm1+1>(unsigned long)time(NULL))) 
			    net_listen();

			ceigrp=ceigrp->next;
		    }
		    c=c->next;
		} /* end of temporary result loop */
	    } /* end if EIGRP scan with no destination */
	} /* end of EIGRP selected scan */

    } /* end of active mode */ else {
	printf("passive listen ... (hit Ctrl-C to finish)\n"); fflush(stdout);
    }

    if (!cfg.cont) {
	/* ... continue capture, may be there are still responses */
	if (!cfg.passive)
	    printf("\nContinuing capture ... (hit Ctrl-C to finish)\n");
	while (!stop_flag) net_listen();
    } else {
	printf("\n");
    }

    print_results();

    /* at the end of the day, close our socket */
    pcap_close(cap);
    if (!cfg.inputfile) {
	close(atsock);
    }

    clean_results();

    return (0);
}




/********************** FUNCTIONS **********************/

void 	net_listen(void) {
    u_char		*pcap_data, *ppacket;
    struct pcap_pkthdr	pcap_head,phead;

    if ((pcap_data=(u_char *)pcap_next(cap,&pcap_head))!=NULL) {
	/* make a local copy of the data, 
	 * pcap will overwrite the buffer if needed */
	
	memcpy(&phead,&pcap_head,sizeof(struct pcap_pkthdr));
	ppacket=(u_char *)smalloc(phead.caplen);
	memcpy(ppacket,pcap_data,phead.caplen);

	evaluate_packet(ppacket,phead.caplen);

	free(ppacket);
    } else if (cfg.inputfile) stop_flag++;
}

void	evaluate_packet(u_char *frame,int frame_length) {
    struct ether_header		*eth;
    iphdr_t			*ip;
    igrp_t			*igrp;
    igrp_system_entry_t		*isys;
    icmphdr_t			*icmph;
    irdp_t			*irdph;
    irdp_rec_t			*irdpr;
    udphdr_t			*udp;
    ripv1hdr_t			*rip1;
    ripv1addr_t			*raddr;
    ripv2addr_t			*raddr2; /* size is equal to v1 ... anyway */
    eigrp_t			*eigrp;
    eigrpsoft_t			*eigrps;
    eigrpintroute_t		*eigrpr;
    hsrp_t			*hsrp;
    ospf_header_t		*ospfh;

    /* for CDP */
    struct eth_LLC		*eth_llc;
    u_char			*cdpbegin;
    cdp_generic_t		*cdpg;
    struct cdp_address_entry	*cdpa;
    unsigned int		cdpdatalength;
    struct in_addr 		caa;
    
    int				i;
    

    if (cfg.verbose>2) printf("... Packet ...\n");

    eth=(struct ether_header *)frame;
    if (ntohs(eth->ether_type)==ETHERTYPE_IP) {

	if (cfg.verbose>2) printf("\tIP\n");
	ip=(iphdr_t *)(frame+sizeof(struct ether_header));

	/* if it is from myself, igore it */
	if (!memcmp(&(ip->saddr),
		    &(packet_ifconfig.ip.s_addr),IP_ADDR_LEN)) return;
	if (cfg.verbose>2) printf("\tnot me\n");
	/* if it is from the spoofed self, igore it */
	if (!memcmp(&(ip->saddr),&(cfg.src),IP_ADDR_LEN)) return;

	/* IGRP  ??? */
	if (ip->protocol==IPPROTO_IGRP) {

	    /* size check */
	    if ((sizeof(struct ether_header)+sizeof(iphdr_t)+sizeof(igrp_t))
		    >frame_length) return;
	    if (cfg.verbose>2) printf("\tigrp\n");
	    igrp=(igrp_t *)(frame+sizeof(struct ether_header)+
		    sizeof(iphdr_t));

	    if (cfg.verbose>1) { printf("%c",FCHAR_IGRP); fflush(stdout); }

	    /* if this wasn't an update, just add the router */
	    if (igrp->opcode!=IGRP_OPCODE_UPDATE) {
		add_route(CAP_IGRP,&(ip->saddr),
			ntohs(igrp->autosys),NULL); 

	    } else {

		/* now, check for routes in the update */
		if (cfg.verbose>2) 
		    printf("\t%d exterior routes in update"
			    " (experimental)\n"
			    "\t%d interior routes in update"
			    " (experimental)\n"
			    "\t%d system routes in update\n",
			    ntohs(igrp->exterior),
			    ntohs(igrp->interior),
			    ntohs(igrp->system));


		for (i=0;i<ntohs(igrp->system);i++) {

		    if (
			    (sizeof(struct ether_header)+
			    sizeof(iphdr_t)+
			    sizeof(igrp_t)+
			    (i+1*sizeof(igrp_system_entry_t)))
			    >frame_length) {
			fprintf(stderr,"WARNING: IGRP packet says it contains"
				" %d system routes but ends after %d\n",
				igrp->system,i);
			return ;
		    }
		    isys=(igrp_system_entry_t *)(frame+
			    sizeof(struct ether_header)+
			    sizeof(iphdr_t)+
			    sizeof(igrp_t)+
			    (i*sizeof(igrp_system_entry_t)));

		    add_route(CAP_IGRP,&(ip->saddr),
			    ntohs(igrp->autosys),isys); 
		} 
	    } /* end of UPDATE */

	    /* end of IGRP */
	} else if (ip->protocol==IPPROTO_ICMP) {
	    /* it's an ICMP */
	    if (cfg.verbose>2) printf("\ticmp\n");
	    icmph=(icmphdr_t *)(frame+sizeof(struct ether_header)+
		    sizeof(iphdr_t));
	    if (icmph->type==ICMP_ROUTER_ADVERT) {
		/* it's actually a router advertisement */
		if (cfg.verbose>2) printf("\tIRDP\n");
		if (cfg.verbose>1) { printf("%c",FCHAR_IRDP); fflush(stdout); }

		if ( (sizeof(struct ether_header)+sizeof(iphdr_t)+
			    sizeof(icmphdr_t)+sizeof(irdp_t))
			>frame_length) return;
		irdph=(irdp_t *)(frame+sizeof(struct ether_header)+
			sizeof(iphdr_t)+sizeof(icmphdr_t));

		for (i=0;i<(irdph->num_addr);i++) {
		    if ( (sizeof(struct ether_header)
			    +sizeof(iphdr_t)
			    +sizeof(icmphdr_t)
			    +sizeof(irdp_t)
			    +(i+1*sizeof(irdp_rec_t)))
			    >frame_length) {
			fprintf(stderr,"WARNING: IRDP packet says it contains"
				" %d routes but ends after %d\n",
				irdph->num_addr,i);
			return ;
		    }
		    irdpr=(irdp_rec_t *)(frame
			    +sizeof(struct ether_header)
			    +sizeof(iphdr_t)
			    +sizeof(icmphdr_t)
			    +sizeof(irdp_t)
			    +(i*sizeof(irdp_rec_t)));

		    add_route(CAP_IRDP,&(ip->saddr),
			    0,irdpr); 
		} /* end of for */
	    } /* end of ICMP IRDP */
	} /* end if IPPROTO_ICMP */
	else if (ip->protocol==IPPROTO_UDP) {
	    if (cfg.verbose>2) printf("\tudp\n");
	    udp=(udphdr_t *)(frame+sizeof(struct ether_header)+
		    sizeof(iphdr_t));
	    if (ntohs(udp->dport)==RIP_PORT) {
		if ((sizeof(struct ether_header)+sizeof(iphdr_t)+
			sizeof(udphdr_t)+sizeof(ripv1hdr_t))>frame_length) 
		    return;
		/* RIP ! */
		rip1=(ripv1hdr_t *)(frame+sizeof(struct ether_header)+
			sizeof(iphdr_t)+sizeof(udphdr_t));
		if (rip1->version==1) {
		    if (cfg.verbose>2) printf("\tRIPv1\n");
		    if (cfg.verbose>1) { 
			printf("%c",FCHAR_RIPv1); 
			fflush(stdout);
		    }

		    i=1;
		    while ( 
			    (sizeof(struct ether_header)
			    +sizeof(iphdr_t)
			    +sizeof(udphdr_t)
			    +sizeof(ripv1hdr_t)
			    +i*sizeof(ripv1addr_t))<=frame_length) {

			raddr=(ripv1addr_t *)
			    (frame+sizeof(iphdr_t)+sizeof(udphdr_t)+
			     sizeof(struct ether_header)+sizeof(ripv1hdr_t)+
			     (i-1)*sizeof(ripv1addr_t));
			if (ntohs(raddr->addrfamily)==2) {
			    add_route(CAP_RIPv1,&(ip->saddr),0,raddr); 
			} else {
			    if (cfg.verbose) 
				printf("RIPv1 addr not IP.\n");
			}
			i++;
		    }
		} /* end RIPv1 */
		else if (rip1->version==2) {
		    if (cfg.verbose>2) printf("\tRIPv2\n");
		    if (cfg.verbose>1) { 
			printf("%c",FCHAR_RIPv2); 
			fflush(stdout);
		    }

		    i=1;
		    while ( 
				(sizeof(struct ether_header)
				+sizeof(iphdr_t)
				+sizeof(udphdr_t)
				+sizeof(ripv2hdr_t)
				+i*sizeof(ripv2addr_t))<=frame_length) {

			raddr2=(ripv2addr_t *)
			    (frame+sizeof(iphdr_t)+sizeof(udphdr_t)+
			     sizeof(struct ether_header)+sizeof(ripv2hdr_t)+
			     (i-1)*sizeof(ripv2addr_t));
			if (ntohs(raddr2->addrfamily)==2) {
			    add_route(CAP_RIPv2,&(ip->saddr),0,raddr2); 
			} else if (ntohs(raddr2->addrfamily)==0xFFFF) {
			    add_route(CAP_RIPv2auth,&(ip->saddr),0,raddr2); 
			} else {
			    if (cfg.verbose) 
				printf("RIPv2 addr not IP or auth.\n");
			}
			i++;
		    }
		} /* end RIPv2 */
		else 
		    fprintf(stderr,"The program seems to be stoneage:"
			    " RIP version %u ???\n",rip1->version);
	    } /* end of RIP (UDP port)*/
	    else if (ntohs(udp->dport)==HSRP_PORT) {
		if ((sizeof(struct ether_header)+sizeof(iphdr_t)+
			sizeof(udphdr_t)+sizeof(hsrp_t))>frame_length) 
		    return;
		hsrp=(hsrp_t *)(frame+sizeof(struct ether_header)+
			sizeof(iphdr_t)+sizeof(udphdr_t));
		if (cfg.verbose>2) printf("\tHSRP\n");
		if (cfg.verbose>1) { printf("%c",FCHAR_HSRP); fflush(stdout);}
		if (hsrp->opcode==HSRP_OPCODE_HELLO) 
		    /* only HELLOs are supported */
		    add_route(CAP_HSRP,&(ip->saddr),0,hsrp); 
	    } /* end of HSRP port */
	} /* enf of UDP */
	else if (ip->protocol==IPPROTO_EIGRP) {
	    if (cfg.verbose>2) printf("\teigrp\n");
	    if (cfg.verbose>1) { printf("%c",FCHAR_EIGRP); fflush(stdout);}
	    eigrp=(eigrp_t *)(frame+sizeof(struct ether_header)
		    +sizeof(iphdr_t));
	    if (eigrp->opcode==EIGRP_HELLO) {
		int	f=0;
		i=0;
		while ( 
			(sizeof(struct ether_header)
			+sizeof(iphdr_t)
			+sizeof(eigrp_t)
			+i
			+sizeof(eigrpsoft_t))<=frame_length) {
		    /* as long as there could be still a software
		     * section in there ... */
		    eigrps=(eigrpsoft_t *)(frame+sizeof(struct ether_header)
			    +sizeof(iphdr_t) 
			    +sizeof(eigrp_t) 
			    +i);
		    i+=ntohs(eigrps->length);
		    if (ntohs(eigrps->type)==EIGRP_TYPE_SOFT) {
			add_route(CAP_EIGRP,&(ip->saddr),
				ntohl(eigrp->as),eigrps); 
			f++;
			break;
		    }
		} /* end of loop through eigrp */
		if (!f) 
		    /* if there was no software info in EIGRP HELLO, add it */
		    add_route(CAP_EIGRP,&(ip->saddr),
			    ntohl(eigrp->as),NULL); 
	    } /* end of HELLO */ else if (eigrp->opcode==EIGRP_UPDATE) {
		i=0;
		while ( 
			(sizeof(struct ether_header)
			+sizeof(iphdr_t)
			+sizeof(eigrp_t)
			+i
			+sizeof(eigrpintroute_t))<=frame_length) {
		    /* as long as there could be one more 
		     * internal route in there ... */
		    eigrpr=(eigrpintroute_t *)(frame+sizeof(struct ether_header)
			    +sizeof(iphdr_t) 
			    +sizeof(eigrp_t) 
			    +i);
		    i+=ntohs(eigrpr->length);
		    if ((ntohs(eigrpr->type)==EIGRP_TYPE_IN_ROUTE) 
			    ||(ntohs(eigrpr->type)==EIGRP_TYPE_EX_ROUTE)) {
			if (cfg.verbose>1) { 
			    printf("%c",FCHAR_EIGRP_RT); fflush(stdout);
			}
			add_route(CAP_EIGRP_RT,&(ip->saddr),
				ntohl(eigrp->as),eigrpr); 
		    }
		} /* end of loop through eigrp */
	    } /* end of UPDATE */
	} /* end of EIGRP */
	else if (ip->protocol==IPPROTO_OSPF) {
	    if (cfg.verbose>2) printf("\tOSPF\n");
	    if (cfg.verbose>1) { printf("%c",FCHAR_OSPF); fflush(stdout);}

	    if ((sizeof(struct ether_header)+sizeof(iphdr_t)+
			sizeof(ospf_header_t)+sizeof(ospf_hello_t))
		    >frame_length) {
		add_route(CAP_OSPF,&(ip->saddr),0,NULL);
	    } else {
		/* there is enough stuff in it to be OSPF hello */
		ospfh=(ospf_header_t *)(frame+sizeof(struct ether_header)
			+sizeof(iphdr_t));
		if ((ospfh->version!=2)||(ospfh->type!=OSPF_HELLO))
		    add_route(CAP_OSPF,&(ip->saddr),0,NULL);
		else 
		    /* version 2 supported, it's Hello and long enough */
		    add_route(CAP_OSPF,&(ip->saddr),0,ospfh);
	    }
	} /* end of OSPF */
    } /* not IP */ 

    /* maybe it's CDP, this could help */

    eth_llc=(struct eth_LLC *)(frame
	    +sizeof(struct eth_ieee802_3));
    if (
	    (ntohs(eth_llc->proto)==0x2000)&&
	    (eth_llc->orgcode[0]==0x00)&&
	    (eth_llc->orgcode[1]==0x00)&&
	    (eth_llc->orgcode[2]==0x0c)) {
	/* could be CDP */

	if (cfg.verbose>1) { printf("%c",FCHAR_CDP); fflush(stdout); } 
	else if (cfg.verbose>2) printf("CDP packet ...\n");

	cdpbegin=(u_char *)(frame
		+sizeof(struct eth_ieee802_3)
		+sizeof(struct eth_LLC)
		+sizeof(struct cdphdr));
	cdpdatalength=(frame_length
		-sizeof(struct eth_ieee802_3)
		-sizeof(struct eth_LLC)
		-sizeof(struct cdphdr));
	cdpg=(cdp_generic_t*)cdpbegin;

	do {
	    if (ntohs(cdpg->type)==TYPE_ADDRESS) {
		if (cfg.verbose>2) 
		    printf("Number of addr's in it: %d\n",
			ntohl(*((u_int32_t *)
				((u_char*)cdpg+2*sizeof(u_int16_t)))
			    ));

		cdpa=(struct cdp_address_entry *)((u_char*)cdpg+
			2*sizeof(u_int16_t)+sizeof(u_int32_t));
		if (cdpa->proto!=0xCC) {
		    if (cfg.verbose) printf("CDP not speaking IP at"
			    "%02x:%02x:%02x:%02x:%02x:%02x\n",
			    *((u_char*)frame+6)&0xFF,
			    *((u_char*)frame+7)&0xFF,
			    *((u_char*)frame+8)&0xFF,
			    *((u_char*)frame+9)&0xFF,
			    *((u_char*)frame+10)&0xFF,
			    *((u_char*)frame+11)&0xFF);
		    memset(&(caa),0,sizeof(caa));
		    add_route(CAP_CDP,&caa,cdpdatalength,(u_char*)cdpbegin); 
		} else {
		    memcpy(&(caa.s_addr),&(cdpa->addr),IP_ADDR_LEN);
		    add_route(CAP_CDP,&caa,cdpdatalength,(u_char*)cdpbegin); 
		}
	    }
	    
	    cdpg=(cdp_generic_t *)((u_char*)cdpg+ntohs(cdpg->length));

	} while (((u_char*)cdpg-(u_char*)frame)<frame_length); 
	/* means: loop as long through the CDP sections until the pointer
	 * would reach outside the packet */
    }
    return;
}



void	signaler(int sig) {
    if (!stop_flag) 
	pcap_close(cap);
    stop_flag++;
    if (cfg.verbose>2)
	fprintf(stderr,"\nSignal received.\n");
}


int	initialize_pcap(void) {
#define PATTERNSTRING	"not src host "
#define IPSTRLEN	16
    char                pcap_err[PCAP_ERRBUF_SIZE]; /* buffer for pcap errors */
    struct bpf_program  cfilter;                   /* the compiled filter */
    bpf_u_int32		network,netmask;

    char		tipstr[IPSTRLEN+1];
    char		*notfilter;

    if (!cfg.inputfile) {
	/* prepare filter */
	memset(&tipstr,0,IPSTRLEN+1);
	strcpy(tipstr,inet_ntoa(cfg.src));
	notfilter=(char *)smalloc(strlen(PATTERNSTRING)+IPSTRLEN+1);
	strcpy(notfilter,PATTERNSTRING);
	strcat(notfilter,tipstr);

	/* get my network and netmask */
	if (pcap_lookupnet(cfg.device,&network,&netmask,pcap_err)!=0) {
	    fprintf(stderr,"pcap_lookupnet(): %s\n",pcap_err);
	    return (-1);
	}

	/* open the sniffer */
	if ((cap=pcap_open_live(cfg.device,CAPLENGTH,
			cfg.prom, /* in promi mode */
			// 0, /* no timeouts sometimes don't work ...*/
			//1000, /* sometimes doesn't work ...*/
			1, /* sometimes doesn't work ...*/
			pcap_err))==NULL) {
	    fprintf(stderr,"pcap_open_live(): %s\n",pcap_err);
	    return (-1);
	}

	if (pcap_datalink(cap)!=DLT_EN10MB) {
	    fprintf(stderr,"works on Ethernet only, sorry.\n");
	    return (-1);
	}

	if (pcap_compile(cap,&cfilter,notfilter,0,netmask)!=0) {
	    pcap_perror(cap,"pcap_compile()");
	    return (-1);
	}

	if (pcap_setfilter(cap,&cfilter)!=0) {
	    pcap_perror(cap,"pcap_setfilter()");
	    return (-1);
	}
	
	free(notfilter);
    } else {
	if ((cap=pcap_open_offline(cfg.inputfile,pcap_err))==NULL) {
	    fprintf(stderr,"pcap_open_offline(): %s\n",pcap_err);
	    return (-1);
	}
    }

    return 0;
}


/* constructs the IGRP request packet
 * * Returns a pointer to the packet or NULL if failed
 * * returns also the size in *psize */
u_char	*construct_igrp_request(u_int16_t autosys, int *psize) {
#define PADDING_SIZE	14
    u_char			*tpacket;
    iphdr_t			*iph;
    igrp_t			*igrph;
    u_int16_t			cs;		/* checksum */
    char			all_igrp[]="224.0.0.10";


    *psize=PADDING_SIZE+sizeof(igrp_t)+sizeof(iphdr_t);
    tpacket=(u_char *)smalloc(PADDING_SIZE+sizeof(igrp_t)+sizeof(iphdr_t)
	    +3 /* for my checksum function, which sometimes 
		  steps over the mark */
	    );

    /* make up IP packet */
    iph=(iphdr_t *)tpacket;

    iph->version=4;
    iph->ihl=sizeof(iphdr_t)/4;

    iph->tot_len=htons(*psize);
    iph->ttl=IPTTL;
    iph->protocol=IPPROTO_IGRP;

    memcpy(&(iph->saddr.s_addr),&(cfg.src.s_addr),IP_ADDR_LEN);
    if (!cfg.set_dest) 
	inet_aton(all_igrp,(struct in_addr *)&(iph->daddr));
    else
	memcpy(&(iph->daddr.s_addr),&(cfg.dest.s_addr),IP_ADDR_LEN);

    /* make up the IGRP header */
    igrph=(igrp_t *)(tpacket+sizeof(iphdr_t));
    igrph->version=1;
    igrph->opcode=2;		/* Update */
    igrph->edition=0;
    igrph->autosys=htons(autosys);
    igrph->interior=0;
    igrph->system=0;
    igrph->exterior=0;

    /* make up checksum */
    cs=chksum((u_char *)igrph,(*psize-sizeof(iphdr_t)));
    igrph->checksum=cs;

    return tpacket;
}


/* constructs the EIGRP request packet
 * * Returns a pointer to the packet or NULL if failed
 * * returns also the size in *psize */
u_char	*construct_eigrp_request(struct in_addr *dd, 
	u_int32_t autosys, int *psize) {
    u_char			*tpacket;
    iphdr_t			*iph;
    eigrp_t			*eigrph;
    eigrppara_t			*epara;
    eigrpsoft_t			*esoft;
    u_int16_t			cs;		/* checksum */
    char			all_igrp[]="224.0.0.10";


    *psize=sizeof(iphdr_t)+sizeof(eigrp_t)
	+sizeof(eigrppara_t)+sizeof(eigrpsoft_t);
    tpacket=(u_char *)smalloc(*psize
	    +3 /* for my checksum function, which sometimes 
		  steps over the mark */
	    );

    /* make up IP packet */
    iph=(iphdr_t *)tpacket;

    iph->version=4;
    iph->ihl=sizeof(iphdr_t)/4;

    iph->tot_len=htons(*psize);
    iph->ttl=IPTTL;
    iph->protocol=IPPROTO_EIGRP;

    memcpy(&(iph->saddr.s_addr),&(cfg.src.s_addr),IP_ADDR_LEN);
    if (dd==NULL) 
	inet_aton(all_igrp,(struct in_addr *)&(iph->daddr));
    else
	memcpy(&(iph->daddr.s_addr),&(dd->s_addr),IP_ADDR_LEN);

    /* make up the IGRP header */
    eigrph=(eigrp_t *)(tpacket+sizeof(iphdr_t));
    eigrph->version=2;
    eigrph->opcode=EIGRP_HELLO;
    eigrph->as=htonl(autosys);

    epara=(eigrppara_t *)(tpacket+sizeof(iphdr_t)+sizeof(eigrp_t));
    epara->type=htons(EIGRP_TYPE_PARA);
    epara->length=htons(sizeof(eigrppara_t));
    epara->k1=epara->k3=1;
    epara->holdtime=htons(15);

    esoft=(eigrpsoft_t *)(tpacket+sizeof(iphdr_t)
	    +sizeof(eigrp_t)+sizeof(eigrppara_t));
    esoft->type=htons(EIGRP_TYPE_SOFT);
    esoft->length=htons(sizeof(eigrpsoft_t));
    esoft->iosmaj=12;
    esoft->iosmin=2;
    esoft->eigrpmaj=1;
    esoft->eigrpmin=0;

    /* make up checksum */
    cs=chksum((u_char *)eigrph,(*psize-sizeof(iphdr_t)));
    eigrph->checksum=cs;

    return tpacket;
}

/* constructs the IRDP request packet
 * * Returns a pointer to the packet or NULL if failed
 * * returns also the size in *psize */
u_char	*construct_irdp_request(int *psize) {
    u_char			*tpacket;
    iphdr_t			*iph;
    irdp_solicitation_t		*irdph;
    u_int16_t			cs;		/* checksum */


    *psize=sizeof(irdp_solicitation_t)+sizeof(iphdr_t);
    tpacket=(u_char *)smalloc(sizeof(irdp_solicitation_t)+sizeof(iphdr_t)
	    +3 /* for my checksum function, which sometimes 
		  steps over the mark */
	    );

    /* make up IP packet */
    iph=(iphdr_t *)tpacket;

    iph->version=4;
    iph->ihl=sizeof(iphdr_t)/4;

    iph->tot_len=htons(*psize);
    iph->ttl=IPTTL;
    iph->protocol=IPPROTO_ICMP;

    memcpy(&(iph->saddr.s_addr),&(cfg.src.s_addr),IP_ADDR_LEN);
    memcpy(&(iph->daddr.s_addr),&(cfg.dest.s_addr),IP_ADDR_LEN);

    /* make up the irdp_solicitation_t header */
    irdph=(irdp_solicitation_t *)(tpacket+sizeof(iphdr_t));
    irdph->type=ICMP_SOLICITATION;
    irdph->code=0;
    irdph->checksum=0;
    irdph->reserved=0;

    /* make up checksum */
    cs=chksum((u_char *)irdph,(*psize-sizeof(iphdr_t)));
    irdph->checksum=cs;

    return tpacket;
}

/* constructs the RIP1 request packet
 * * Returns a pointer to the packet or NULL if failed
 * * returns also the size in *psize */
u_char	*construct_rip_request(int *psize) {
    u_char			*tpacket;
    iphdr_t			*iph;
    udphdr_t			*udp;
    ripv1hdr_t                  *rip;
    ripv1addr_t                 *ripaddr;


    *psize=sizeof(udphdr_t)+sizeof(iphdr_t)+
	sizeof(ripv1hdr_t)+sizeof(ripv1addr_t);
    tpacket=(u_char *)smalloc(sizeof(udphdr_t)+sizeof(iphdr_t)+
	    sizeof(ripv1hdr_t)+sizeof(ripv1addr_t)
	    +3 /* for my checksum function, which sometimes 
		  steps over the mark */
	    );

    /* make up IP packet */
    iph=(iphdr_t *)tpacket;

    iph->version=4;
    iph->ihl=sizeof(iphdr_t)/4;

    iph->tot_len=htons(*psize);
    iph->ttl=IPTTL;
    iph->protocol=IPPROTO_UDP;

    memcpy(&(iph->saddr.s_addr),&(cfg.src.s_addr),IP_ADDR_LEN);
    memcpy(&(iph->daddr.s_addr),&(cfg.dest.s_addr),IP_ADDR_LEN);

    /* make up the UDP header */
    udp=(udphdr_t *)(tpacket+sizeof(iphdr_t));
    udp->sport=htons(RIP_PORT);
    udp->dport=htons(RIP_PORT);
    udp->length=htons(*psize-sizeof(iphdr_t));

    /* make up the RIPv1 request */
    rip=(ripv1hdr_t *)(tpacket+sizeof(iphdr_t)+sizeof(udphdr_t));
    rip->command=RIP_COMMAND_REQUEST;
    rip->version=1;

    /* metric has to be 16 in a all-routes request */
    ripaddr=(ripv1addr_t *)(tpacket+sizeof(iphdr_t)+sizeof(udphdr_t)+
	    sizeof(ripv1hdr_t));
    ripaddr->metric=htonl(0x10);

    return tpacket;
}

/* constructs the RIP2 request packet
 * * Returns a pointer to the packet or NULL if failed
 * * returns also the size in *psize */
u_char	*construct_rip2_request(int *psize) {
    u_char			*tpacket;
    iphdr_t			*iph;
    udphdr_t			*udp;
    char			all_rip2[]="224.0.0.9";
    ripv2hdr_t                  *rip;
    ripv2addr_t                 *ripaddr;


    *psize=sizeof(udphdr_t)+sizeof(iphdr_t)+
	sizeof(ripv2hdr_t)+sizeof(ripv2addr_t);
    tpacket=(u_char *)smalloc(sizeof(udphdr_t)+sizeof(iphdr_t)+
	    sizeof(ripv2hdr_t)+sizeof(ripv2addr_t)
	    +3 /* for my checksum function, which sometimes 
		  steps over the mark */
	    );

    /* make up IP packet */
    iph=(iphdr_t *)tpacket;

    iph->version=4;
    iph->ihl=sizeof(iphdr_t)/4;

    iph->tot_len=htons(*psize);
    iph->ttl=IPTTL;
    iph->protocol=IPPROTO_UDP;

    memcpy(&(iph->saddr.s_addr),&(cfg.src.s_addr),IP_ADDR_LEN);
    if (!cfg.set_dest)
	inet_aton(all_rip2,(struct in_addr *)&(iph->daddr));
    else
	memcpy(&(iph->daddr.s_addr),&(cfg.dest.s_addr),IP_ADDR_LEN);

    /* make up the UDP header */
    udp=(udphdr_t *)(tpacket+sizeof(iphdr_t));
    udp->sport=htons(RIP_PORT);
    udp->dport=htons(RIP_PORT);
    udp->length=htons(*psize-sizeof(iphdr_t));

    /* make up the RIPv1 request */
    rip=(ripv2hdr_t *)(tpacket+sizeof(iphdr_t)+sizeof(udphdr_t));
    rip->command=RIP_COMMAND_REQUEST;
    rip->version=2;

    /* metric has to be 16 in a all-routes request */
    ripaddr=(ripv2addr_t *)(tpacket+sizeof(iphdr_t)+sizeof(udphdr_t)+
	    sizeof(ripv2hdr_t));
    ripaddr->metric=htonl(0x10);

    return tpacket;
}


void	usage(char *n) {
    printf(
	    "%s [-v[v[v]]] -i <interface> [-ApcMs] [-P IER12]\n"
	    "\t[-a <autonomous system start> -b <autonomous system stop>]\n"
	    "\t[-S <spoofed source IP>] [-D <destination ip>]\n"
	    "\t[-T <packets per delay>]\n"
	    "\t[-r <filename>]\n",
	    n);
    exit (1);
}


int	add_route(int rtype,struct in_addr *addr,unsigned int as,void *data) {
    /* For all routing protocols, the handling is as follows:
     * 		- look for an entry in the result_t list that has the same 
     * 		  address. If there is such an entry, use this. Otherwise 
     * 		  create one. 
     * 		- For the particular protocol, check if the information is 
     * 		  already in there (based on fields depending on the protocol
     * 		  such as the AS) and add the info in the tree as needed.
     * 		- CDP is different. It works the same way for devices running 
     * 		  CDP and IP - but devices not running IP (such as switches)
     * 		  will be included as router 0.0.0.0. The CDP subtree looks for 
     * 		  the device name as key (Oops - this is what cisco did ;)
     * 		  WARNING: variable "as" is used to transport the frame length
     * 		  minus Ethernet,LLC and CdpHdr !!!
     */
    result_t		*current,*c2;
    RES_route_igrp_t	*c_igrp;
    RES_route_irdp_t	*c_irdp;
    RES_route_ripv1_t	*c_rip;
    RES_route_ripv2_t	*c_rip2;
    RES_route_eigrp_t	*c_eigrp;
    RES_route_eigrprt_t	*c_eigrpr;
    RES_route_hsrp_t	*c_hsrp;
    RES_route_ospf_t	*c_ospf;
    RES_cdp_info_t	*c_cdp,*c2_cdp;
    igrp_system_entry_t	*isys;
    irdp_rec_t		*irdpr;
    ripv1addr_t		*rip1a;
    ripv2addr_t		*rip2a;
    ripv2auth_t		*rip2auth;
    eigrpsoft_t		*eigrps;
    eigrpextroute_t	*eigrper;
    eigrpintroute_t	*eigrpir;
    hsrp_t		*hsrp;
    ospf_header_t	*ospfh;
    ospf_hello_t	*ospfl;
    cdp_generic_t	*cdprec;
    u_int32_t		temp;
    int			i;

    current=anchor;
    c2=NULL;

    /* look for already exisiting one */
    while (current!=NULL) {
	if (!memcmp(&(current->addr),addr,sizeof(struct in_addr))) break;
	c2=current;
	current=current->next;
    }

    /* if not existing, add one */
    if (current==NULL) {
	current=smalloc(sizeof(result_t));
	memcpy(&(current->addr),addr,sizeof(struct in_addr));

	if (c2) c2->next=current;
	/* if it is the first, make it anchor */
	if (anchor==NULL) anchor=current;
    }

    /* may be there are no routes in it ... */
    if (rtype==0) return 0;

    switch (rtype) { 
	case CAP_IGRP: /* add an IGRP route */
	    current->capa=current->capa|CAP_IGRP;
	    isys=(igrp_system_entry_t *)data;
	    
	    if (current->igrp==NULL) {
		current->igrp=(RES_route_igrp_t *)
		    smalloc(sizeof(RES_route_igrp_t));
		c_igrp=current->igrp;
	    } else {
		c_igrp=current->igrp;
		while (c_igrp!=NULL) {
		    if (
			    (!memcmp(&(c_igrp->dest.s_addr),
				     &(isys->destination),3))
			    &&
			    (c_igrp->as==as))
			/* destination already known for this router */
			return 1;
		    c_igrp=c_igrp->next;
		}
		/* go to the last valid entry */
		c_igrp=current->igrp;
		while (c_igrp->next!=NULL) c_igrp=c_igrp->next;
		c_igrp->next=(RES_route_igrp_t *)
		    smalloc(sizeof(RES_route_igrp_t));
		c_igrp=c_igrp->next;
	    }
	    /* at this point c_igrp points to an empty record */
		
	    if (data!=NULL) {
		memcpy(&(c_igrp->dest.s_addr),&(isys->destination),3);
		memset(&temp,0,sizeof(temp));
		memcpy(((u_int8_t *)&temp)+1,&(isys->delay),3);
		c_igrp->delay=ntohl(temp);
		memset(&temp,0,sizeof(temp));
		memcpy(((u_int8_t *)&temp)+1,&(isys->bandwith),3);
		c_igrp->bandw=ntohl(temp);
		c_igrp->mtu=ntohs(isys->mtu);
		c_igrp->reliability=isys->reliability;
		c_igrp->load=isys->load;
		c_igrp->hopcount=isys->hopcount;
		c_igrp->as=as;
	    }

	    break;

	    /* 
	     * IRDP 
	     */
	case CAP_IRDP:
	    current->capa=current->capa|CAP_IRDP;
	    irdpr=(irdp_rec_t *)data;
	    
	    if (current->irdp==NULL) {
		current->irdp=(RES_route_irdp_t *)
		    smalloc(sizeof(RES_route_irdp_t));
		c_irdp=current->irdp;
	    } else {
		c_irdp=current->irdp;
		while (c_irdp!=NULL) {
		    if (!memcmp(&(c_irdp->dest.s_addr),
				&(irdpr->addr),IP_ADDR_LEN))
			/* destination already known for this router */
			return 1;
		    c_irdp=c_irdp->next;
		}
		/* go to the last valid entry */
		c_irdp=current->irdp;
		while (c_irdp->next!=NULL) c_irdp=c_irdp->next;
		c_irdp->next=(RES_route_irdp_t *)
		    smalloc(sizeof(RES_route_irdp_t));
		c_irdp=c_irdp->next;
	    }
	    /* at this point c_irdp points to an empty record */

	    memcpy(&(c_irdp->dest.s_addr),&(irdpr->addr),IP_ADDR_LEN);
	    c_irdp->preference=ntohl(irdpr->pref);
	    break;


	    /* 
	     * RIPv1
	     */
	case CAP_RIPv1:
	    current->capa=current->capa|CAP_RIPv1;
	    rip1a=(ripv1addr_t *)data;

	    if (current->rip1==NULL) {
		current->rip1=(RES_route_ripv1_t *)
		    smalloc(sizeof(RES_route_ripv1_t));
		c_rip=current->rip1;
	    } else {
		c_rip=current->rip1;
		while (c_rip!=NULL) {
		    if (!memcmp(&(c_rip->dest.s_addr),
				&(rip1a->address),IP_ADDR_LEN))
			/* destination already known for this router */
			return 1;
		    c_rip=c_rip->next;
		}
		/* go to the last valid entry */
		c_rip=current->rip1;
		while (c_rip->next!=NULL) c_rip=c_rip->next;
		c_rip->next=(RES_route_ripv1_t *)
		    smalloc(sizeof(RES_route_ripv1_t));
		c_rip=c_rip->next;
	    }
	    /* at this point c_rip points to an empty record */

	    memcpy(&(c_rip->dest.s_addr),&(rip1a->address),IP_ADDR_LEN);
	    c_rip->metric=ntohl(rip1a->metric);
	    break;


	    /* 
	     * RIPv2
	     */
	case CAP_RIPv2:
	    current->capa=current->capa|CAP_RIPv2;
	    rip2a=(ripv2addr_t *)data;

	    if (current->rip2==NULL) {
		current->rip2=(RES_route_ripv2_t *)
		    smalloc(sizeof(RES_route_ripv2_t));
		c_rip2=current->rip2;
	    } else {
		c_rip2=current->rip2;
		while (c_rip2!=NULL) {
		    if (!memcmp(&(c_rip2->dest.s_addr),
				&(rip2a->address),IP_ADDR_LEN))
			/* destination already known for this router */
			return 1;
		    c_rip2=c_rip2->next;
		}
		/* go to the last valid entry */
		c_rip2=current->rip2;
		while (c_rip2->next!=NULL) c_rip2=c_rip2->next;
		c_rip2->next=(RES_route_ripv2_t *)
		    smalloc(sizeof(RES_route_ripv2_t));
		c_rip2=c_rip2->next;
	    }
	    /* at this point c_rip points to an empty record */

	    memcpy(&(c_rip2->dest.s_addr),&(rip2a->address),IP_ADDR_LEN);
	    memcpy(&(c_rip2->mask.s_addr),&(rip2a->netmask),IP_ADDR_LEN);
	    memcpy(&(c_rip2->nexthop.s_addr),&(rip2a->nexthop),IP_ADDR_LEN);
	    c_rip2->metric=ntohl(rip2a->metric);
	    c_rip2->routetag=ntohs(rip2a->routetag);
	    break;


	    /* 
	     * RIPv2 Authentication
	     */
	case CAP_RIPv2auth:
	    current->capa=current->capa|CAP_RIPv2auth;
	    rip2auth=(ripv2auth_t *)data;

	    current->rip2auth_type=htons(rip2auth->authtype);
	    memset(&(current->rip2pw),0,sizeof(current->rip2pw));
	    memcpy(&(current->rip2pw),&(rip2auth->auth),16);
	    break;

	    /* 
	     * EIGRP passive
	     */
	case CAP_EIGRP:
	    current->capa=current->capa|CAP_EIGRP;
	    eigrps=(eigrpsoft_t *)data;

	    if (current->eigrp==NULL) {
		current->eigrp=(RES_route_eigrp_t *)
		    smalloc(sizeof(RES_route_eigrp_t));
		c_eigrp=current->eigrp;
	    } else {
		c_eigrp=current->eigrp;
		while (c_eigrp!=NULL) {
		    if (c_eigrp->as==as)
			/* autonomous system already known for this router */
			return 1;
		    c_eigrp=c_eigrp->next;
		}
		/* go to the last valid entry */
		c_eigrp=current->eigrp;
		while (c_eigrp->next!=NULL) c_eigrp=c_eigrp->next;
		c_eigrp->next=(RES_route_eigrp_t *)
		    smalloc(sizeof(RES_route_eigrp_t));
		c_eigrp=c_eigrp->next;
	    }
	    /* at this point c_eigrp points to an empty record */
	    c_eigrp->as=as;

	    if (eigrps!=NULL) {
		c_eigrp->ios_major=eigrps->iosmaj;
		c_eigrp->ios_minor=eigrps->iosmin;
		c_eigrp->eigrp_major=eigrps->eigrpmaj;
		c_eigrp->eigrp_minor=eigrps->eigrpmin;
	    }
	    break;


	    /* 
	     * EIGRP active
	     */
	case CAP_EIGRP_RT:
	    current->capa=current->capa|CAP_EIGRP_RT;
	    /* could be both ... */
	    eigrpir=(eigrpintroute_t *)data;
	    eigrper=(eigrpextroute_t *)data;

	    if (current->eigrpr==NULL) {
		current->eigrpr=(RES_route_eigrprt_t *)
		    smalloc(sizeof(RES_route_eigrprt_t));
		c_eigrpr=current->eigrpr;
	    } else {
		c_eigrpr=current->eigrpr;
		while (c_eigrpr!=NULL) {
		    /* check the EIGRP type */
		    if (ntohs(eigrpir->type)==EIGRP_TYPE_IN_ROUTE) {
			if ((c_eigrpr->as==as)
				&&(!memcmp(&(c_eigrpr->dest.s_addr),
				    &(eigrpir->dest),
				    (int)(eigrpir->prefix_length/8)))
				&&(c_eigrpr->type==ntohs(eigrpir->type))) {
			/* autonomous system and destination
			 * already known for this router */
			    return 1;
			}
		    } else {
			if ((c_eigrpr->as==as)
				&&(!memcmp(&(c_eigrpr->dest.s_addr),
				    &(eigrper->dest),
				    (int)(eigrper->prefix_length/8)))
				&&(c_eigrpr->type==ntohs(eigrper->type))) {
			/* autonomous system and destination
			 * already known for this router */
			    return 1;
			}
		    }
		    c_eigrpr=c_eigrpr->next;
		}
		/* go to the last valid entry */
		c_eigrpr=current->eigrpr;
		while (c_eigrpr->next!=NULL) c_eigrpr=c_eigrpr->next;
		c_eigrpr->next=(RES_route_eigrprt_t *)
		    smalloc(sizeof(RES_route_eigrprt_t));
		c_eigrpr=c_eigrpr->next;
	    }
	    /* at this point c_eigrp points to an empty record */
	    c_eigrpr->as=as;
	    c_eigrpr->type=ntohs(eigrpir->type);
	    memcpy(&(c_eigrpr->nexthop),&(eigrper->nexthop),IP_ADDR_LEN);
	    /* from here one, the packet format changes for external and 
	     * internal routes IP */
	    if (c_eigrpr->type==EIGRP_TYPE_EX_ROUTE) {
		/* external route */
		memcpy(&(c_eigrpr->origrouter),
			&(eigrper->origrouter),IP_ADDR_LEN);
		c_eigrpr->origas=ntohl(eigrper->origas);
		c_eigrpr->externalmetric=ntohl(eigrper->external_metric);
		c_eigrpr->externallink=eigrper->external_link;

		c_eigrpr->delay=ntohl(eigrper->delay);
		c_eigrpr->bandwidth=ntohl(eigrper->bandwidth);
		memset(&temp,0,sizeof(temp));
		memcpy(((u_int8_t *)&temp)+1,&(eigrper->mtu),3);
		c_eigrpr->mtu=ntohs(temp);
		c_eigrpr->hopcount=eigrper->hopcount;
		c_eigrpr->reliability=eigrper->reliability;
		c_eigrpr->load=eigrper->load;

		temp=0xFFFFFFFF;
		for (i=0;i<32-eigrper->prefix_length;i++) 
		    temp=temp<<1;
		temp=htonl(temp);
		memcpy(&(c_eigrpr->netmask),&temp,4);
		memcpy(&(c_eigrpr->dest),&(eigrper->dest),
			(int)(eigrper->prefix_length/8));
	    } else {
		/* internal route */
		c_eigrpr->delay=ntohl(eigrpir->delay);
		c_eigrpr->bandwidth=ntohl(eigrpir->bandwidth);
		memset(&temp,0,sizeof(temp));
		memcpy(((u_int8_t *)&temp)+1,&(eigrpir->mtu),3);
		c_eigrpr->mtu=ntohs(temp);
		c_eigrpr->hopcount=eigrpir->hopcount;
		c_eigrpr->reliability=eigrpir->reliability;
		c_eigrpr->load=eigrpir->load;

		temp=0xFFFFFFFF;
		for (i=0;i<32-eigrpir->prefix_length;i++) 
		    temp=temp<<1;
		temp=htonl(temp);
		memcpy(&(c_eigrpr->netmask),&temp,4);
		memcpy(&(c_eigrpr->dest),&(eigrpir->dest),
			(int)(eigrpir->prefix_length/8));
	    }
	    break;


	    /* 
	     * OSPF passive
	     */
	case CAP_OSPF:
	    current->capa=current->capa|CAP_OSPF;
	    if ((ospfh=(ospf_header_t *)data)==NULL) break;

	    if (current->ospf==NULL) {
		current->ospf=(RES_route_ospf_t *)
		    smalloc(sizeof(RES_route_ospf_t));
		c_ospf=current->ospf;
	    } else {
		c_ospf=current->ospf;
		while (c_ospf!=NULL) {
		    if (
			    (!memcmp(&(c_ospf->area.s_addr),&(ospfh->area),
				     IP_ADDR_LEN))
			    &&
			    (!memcmp(&(c_ospf->source.s_addr),
				     &(ospfh->source),IP_ADDR_LEN))
			    )
			/* area/source already known for this router */
			return 1;
		    c_ospf=c_ospf->next;
		}
		/* go to the last valid entry */
		c_ospf=current->ospf;
		while (c_ospf->next!=NULL) c_ospf=c_ospf->next;
		c_ospf->next=(RES_route_ospf_t *)
		    smalloc(sizeof(RES_route_ospf_t));
		c_ospf=c_ospf->next;
	    }
	    /* at this point c_ospf points to an empty record */

	    if (ospfh!=NULL) {
		memcpy(&(c_ospf->source.s_addr),&(ospfh->source),IP_ADDR_LEN);
		memcpy(&(c_ospf->area.s_addr),&(ospfh->area),IP_ADDR_LEN);
		memcpy(&(c_ospf->authdata),&(ospfh->authdata),8);
		c_ospf->authtype=ntohs(ospfh->authtype);
		ospfl=(ospf_hello_t *)(data+sizeof(ospf_header_t));
		memcpy(&(c_ospf->netmask.s_addr),&(ospfl->netmask),IP_ADDR_LEN);
		memcpy(&(c_ospf->designated.s_addr),
			&(ospfl->designated),IP_ADDR_LEN);
		memcpy(&(c_ospf->backup.s_addr),&(ospfl->backup),IP_ADDR_LEN);
		c_ospf->dead=ntohl(*((u_int32_t *)&(ospfl->dead_interval)));
		c_ospf->prio=ospfl->priority;
		c_ospf->hello=ntohs(ospfl->hello_interval);
	    }
	    break;


	    /* 
	     * HSRP passive
	     */
	case CAP_HSRP:
	    current->capa=current->capa|CAP_HSRP;
	    hsrp=(hsrp_t *)data;

	    if (current->hsrp==NULL) {
		current->hsrp=(RES_route_hsrp_t *)
		    smalloc(sizeof(RES_route_hsrp_t));
		c_hsrp=current->hsrp;
	    } else {
		c_hsrp=current->hsrp;
		while (c_hsrp!=NULL) {
		    if (!memcmp(&(c_hsrp->virtip.s_addr),
				&(hsrp->virtip),IP_ADDR_LEN))
			/* virtual ip already known for this router */
			return 1;
		    c_hsrp=c_hsrp->next;
		}
		/* go to the last valid entry */
		c_hsrp=current->hsrp;
		while (c_hsrp->next!=NULL) c_hsrp=c_hsrp->next;
		c_hsrp->next=(RES_route_hsrp_t *)
		    smalloc(sizeof(RES_route_hsrp_t));
		c_hsrp=c_hsrp->next;
	    }
	    /* at this point c_hsrp points to an empty record */
	    memcpy(&(c_hsrp->virtip.s_addr),hsrp->virtip,IP_ADDR_LEN);
	    memset(&(c_hsrp->auth),0,sizeof(c_hsrp->auth));
	    memcpy(&(c_hsrp->auth),hsrp->auth,8);
	    c_hsrp->version=hsrp->version;
	    c_hsrp->state=hsrp->state;
	    c_hsrp->hello=hsrp->hellotime;
	    c_hsrp->hold=hsrp->holdtime;
	    c_hsrp->group=hsrp->group;
	    c_hsrp->prio=hsrp->prio;
	    break;


	    /*
	     * CDP
	     */
	case CAP_CDP:
	    c_cdp=(RES_cdp_info_t *)smalloc(sizeof(RES_cdp_info_t));
	    /* data should point to the first TLV record in the frame */
	    cdprec=(cdp_generic_t *)data;

	    /* at CDP, we dissect the packet first and add it later */
	    do {
		if (cfg.verbose>2) 
		    printf("CDP add: type %u, length %u\n",
			    ntohs(cdprec->type),ntohs(cdprec->length));

		if (ntohs(cdprec->type)==TYPE_DEVICE_ID) {
		    c_cdp->deviceid=(char*)smalloc(ntohs(cdprec->length)+1);
		    memcpy(c_cdp->deviceid,&(cdprec->value),
			    ntohs(cdprec->length)-4);
		} else if (ntohs(cdprec->type)==TYPE_PORT_ID) {
		    c_cdp->portid=(char*)smalloc(ntohs(cdprec->length)+1);
		    memcpy(c_cdp->portid,&(cdprec->value),
			    ntohs(cdprec->length)-4);
		} else if (ntohs(cdprec->type)==TYPE_CAPABILITIES) {
		    c_cdp->capas=(unsigned long)
			ntohl(*((u_int32_t *)&(cdprec->value)));
		} else if (ntohs(cdprec->type)==TYPE_IOS_VERSION) {
		    c_cdp->software=(char*)smalloc(ntohs(cdprec->length)+1);
		    memcpy(c_cdp->software,&(cdprec->value),
			    ntohs(cdprec->length)-4);
		} else if (ntohs(cdprec->type)==TYPE_PLATFORM) {
		    c_cdp->platform=(char*)smalloc(ntohs(cdprec->length)+1);
		    memcpy(c_cdp->platform,&(cdprec->value),
			    ntohs(cdprec->length)-4);
		} else if (ntohs(cdprec->type)==TYPE_VTP_MGMT) {
		    c_cdp->vtpmgmt=(char*)smalloc(ntohs(cdprec->length)+1);
		    memcpy(c_cdp->vtpmgmt,&(cdprec->value),
			    ntohs(cdprec->length)-4);
		} else if (ntohs(cdprec->type)==TYPE_VLAN) {
		    c_cdp->vlan=ntohs(*((u_int16_t*)&(cdprec->value)));
		} else if (ntohs(cdprec->type)==TYPE_DUPLEX) {
		    c_cdp->duplex=(u_int8_t)cdprec->value;
		} else {
		    if ((cfg.verbose>2) && (ntohs(cdprec->type)!=TYPE_ADDRESS)) {
			fprintf(stderr,"Unknown CDP type %u\n",
				ntohs(cdprec->type));
			fprintf(stderr,"DUMP: %02X %02X %02X %02X %02X %02X\n",
				*((u_int8_t *)cdprec),
				*((u_int8_t *)cdprec+1),
				*((u_int8_t *)cdprec+2),
				*((u_int8_t *)cdprec+3),
				*((u_int8_t *)cdprec+4),
				*((u_int8_t *)cdprec+5));
		    }
		}
		cdprec=(cdp_generic_t *)((u_char*)cdprec+ntohs(cdprec->length));
		/* printf("DEBUG: data = %p, cdprec = %p, cdprec-data = %u,"
			" length = %u\n",
			data,(u_char *)cdprec,((u_char*)cdprec-(u_char*)data),as);
			*/
	    } while ( ((u_char*)cdprec-(u_char*)data)<as);

	    current->capa=current->capa|CAP_CDP;
	    if (current->cdp==NULL) {
		current->cdp=c_cdp;
	    } else {
		c2_cdp=current->cdp;
		while (c2_cdp!=NULL) {
		    if (c_cdp->deviceid!=NULL) {
			if (!strcmp(c2_cdp->deviceid,c_cdp->deviceid)){
			    // source already known for this device 
			    if (cfg.verbose>2) printf("CDP: Device %s"
				    " alread known\n",c_cdp->deviceid);
			    if (c_cdp->deviceid!=NULL) free(c_cdp->deviceid);
			    if (c_cdp->portid!=NULL) free(c_cdp->portid);
			    if (c_cdp->software!=NULL) free(c_cdp->software);
			    if (c_cdp->platform!=NULL) free(c_cdp->platform);
			    if (c_cdp->vtpmgmt!=NULL) free(c_cdp->vtpmgmt);
			    free(c_cdp);
			    return 1;
			}
		    }
		    c2_cdp=c2_cdp->next;
		}
		// go to the last valid entry 
		c2_cdp=current->cdp;
		while (c2_cdp->next!=NULL) c2_cdp=c2_cdp->next;
		c2_cdp->next=c_cdp;
	    } 
	    break;

	default:
	    fprintf(stderr,"Well ... internal function called with "
		    "bullshit argument. bad sign!\n");
	    exit(-15);
    }

    return 0;
}


void	print_results(void) {
    result_t		*current;
    RES_route_igrp_t	*c_igrp;
    RES_route_irdp_t	*c_irdp;
    RES_route_ripv1_t	*c_rip1;
    RES_route_ripv2_t	*c_rip2;
    RES_route_eigrp_t	*c_eigrp;
    RES_route_eigrprt_t	*c_eigrpr;
    RES_route_hsrp_t	*c_hsrp;
    RES_route_ospf_t	*c_ospf;
    RES_cdp_info_t	*c_cdp;

    printf("\n\n>>>Results>>>\n");

    current=anchor;
    while (current!=NULL) {
	printf("Router %15s\t(",inet_ntoa(current->addr));

	/* capabilities */
	if (current->capa&CAP_IGRP) printf("IGRP ");
	if (current->capa&CAP_IRDP) printf("IRDP ");
	if (current->capa&CAP_CDP) printf("CDP ");
	if (current->capa&CAP_RIPv1) printf("RIPv1 ");
	if (current->capa&CAP_RIPv2) printf("RIPv2 ");
	if (current->capa&CAP_EIGRP) printf("EIGRP ");
	if (current->capa&CAP_HSRP) printf("HSRP ");
	if (current->capa&CAP_OSPF) printf("OSPF ");
	printf(")\n");

	/* CDP results */
	c_cdp=current->cdp;
	while(c_cdp!=NULL) {
	    printf("\tCDP [ n/a ]  %17s  %s\n","Device ID",c_cdp->deviceid);
	    if (c_cdp->portid!=NULL);
		printf("\t%13s%17s  %s\n"," ","Port ID",c_cdp->portid);
	    if (c_cdp->platform!=NULL)
		printf("\t%13s%17s  %s\n"," ","Platform",c_cdp->platform);
	    if (c_cdp->vtpmgmt!=NULL)
		printf("\t%13s%17s  %s\n"," ","VTP Mgmt",c_cdp->vtpmgmt);

	    if ((c_cdp->capas&CDP_CAP_LEVEL3_ROUTER)!=0)
		printf("\t%13s%17s  %s\n"," "," ","- Layer 3 Router");
	    if ((c_cdp->capas&CDP_CAP_LEVEL2_TRBR)!=0)
		printf("\t%13s%17s  %s\n"," "," ","- Layer 2 Transparent Bridge");
	    if ((c_cdp->capas&CDP_CAP_LEVEL2_SRB)!=0)
		printf("\t%13s%17s  %s\n"," "," ","- Layer 2 SrcRoute Bridge");
	    if ((c_cdp->capas&CDP_CAP_LEVEL2_SWITCH)!=0)
		printf("\t%13s%17s  %s\n"," "," ","- Layer 2 Switch");
	    if ((c_cdp->capas&CDP_CAP_NETWORK_LAYER)!=0)
		printf("\t%13s%17s  %s\n"," "," ","- Network Layer Protocols");
	    if ((c_cdp->capas&CDP_CAP_FORWARD_IGMP)!=0)
		printf("\t%13s%17s  %s\n"," "," ","- Fwds IGMP to non-routers");
	    if ((c_cdp->capas&CDP_CAP_LEVEL1)!=0)
		printf("\t%13s%17s  %s\n"," "," ","- Provides Level 1 funct");

	    if (c_cdp->vlan!=0) 
		printf("\t%13s%17s  %u\n"," ","Native VLAN",c_cdp->vlan);

	    if (c_cdp->duplex==1) 
		printf("\t%13s%17s  %s\n"," ","Duplex","FULL");
	    else if (c_cdp->duplex==0) 
		printf("\t%13s%17s  %s\n"," ","Duplex","Half");
	    else 
		printf("\t%13s%17s  %u\n"," ","Duplex",c_cdp->duplex);

	    if ((cfg.cdp_show_software)&&(c_cdp->software!=NULL))
		printf("\t%13s%17s \n%s\n"," ","Software ID",c_cdp->software);

	    c_cdp=c_cdp->next;
	}
	/* display all IGRP results */
	c_igrp=current->igrp;
	while (c_igrp!=NULL) {
	    printf("\tIGRP [%5d] %17s  (",c_igrp->as,
		    inet_ntoa(c_igrp->dest));
	    printf("%lu,%lu,%u,%u,%u,%u)\n",
		    c_igrp->delay, c_igrp->bandw, c_igrp->mtu, 
		    c_igrp->reliability, c_igrp->load, c_igrp->hopcount);
	    c_igrp=c_igrp->next;
	}
	/* display all IRDP results */
	c_irdp=current->irdp;
	while (c_irdp!=NULL) {
	    printf("\tIRDP [ n/a ] %17s  (preference %lu)\n",
		    inet_ntoa(c_irdp->dest),c_irdp->preference);
	    c_irdp=c_irdp->next;
	}
	/* RIPv1 */
	c_rip1=current->rip1;
	while (c_rip1!=NULL) {
	    printf("\tRIP1 [ n/a ] %17s  (metric %lu",
		    inet_ntoa(c_rip1->dest),c_rip1->metric);
	    if (c_rip1->metric==16) printf(" [unreachable])\n");
	    else printf(")\n");
	    c_rip1=c_rip1->next;
	}
	/* RIPv2 Authentication */
	if (current->capa&CAP_RIPv2auth) {
	    switch (current->rip2auth_type) {
		case RIP2AUTH_NONE: printf("\tRIP2 [ n/a ] %17s\n","no auth");
				    break;
		case RIP2AUTH_TEXT: printf("\tRIP2 [ n/a ] %17s  ","text auth");
				    printf("(auth '%s')\n",current->rip2pw); 
				    break;
		case RIP2AUTH_MD5:  printf("\tRIP2 [ n/a ] %17s  ","md5 auth");
				    printf("(hash %02X%02X%02X%02X%02X%02X"
					    "%02X%02X%02X%02X%02X%02X%02X"
					    "%02X%02X%02X)\n",
					    current->rip2pw[0]&0xFF,
					    current->rip2pw[1]&0xFF,
					    current->rip2pw[2]&0xFF,
					    current->rip2pw[3]&0xFF,
					    current->rip2pw[4]&0xFF,
					    current->rip2pw[5]&0xFF,
					    current->rip2pw[6]&0xFF,
					    current->rip2pw[7]&0xFF,
					    current->rip2pw[8]&0xFF,
					    current->rip2pw[9]&0xFF,
					    current->rip2pw[10]&0xFF,
					    current->rip2pw[11]&0xFF,
					    current->rip2pw[12]&0xFF,
					    current->rip2pw[13]&0xFF,
					    current->rip2pw[14]&0xFF,
					    current->rip2pw[15]&0xFF);
				    break;
		default: printf("\tRIP2 [ n/a ] %17s\n","unknown auth");
	    }
	}
	/* RIPv2 */
	c_rip2=current->rip2;
	while (c_rip2!=NULL) {
	    printf("\tRIP2 [ n/a ] %17s  /",inet_ntoa(c_rip2->dest));
	    printf("%s, next: ",inet_ntoa(c_rip2->mask));
	    printf("%s\n",inet_ntoa(c_rip2->nexthop));
	    printf("\t%33s"," ");
	    printf("(tag %u, mtr %lu",c_rip2->routetag,c_rip2->metric);
	    if (c_rip2->metric==16) printf(" [unreachable])\n"); 
	    else printf(")\n");
	    c_rip2=c_rip2->next;
	}
	/* EIGRP */
	c_eigrp=current->eigrp;
	while (c_eigrp!=NULL) {
	    printf("\tEIGRP[%5lu] %17s  (IOS %u.%u, EIGRP %u.%u)\n",
		    c_eigrp->as,"",c_eigrp->ios_major,c_eigrp->ios_minor,
		    c_eigrp->eigrp_major, c_eigrp->eigrp_minor);
	    c_eigrp=c_eigrp->next;
	}
	/* EIGRP Routes*/
	c_eigrpr=current->eigrpr;
	while (c_eigrpr!=NULL) {
	    printf("\tEIGRP[%5lu] %17s  ",
		    c_eigrpr->as,inet_ntoa(c_eigrpr->dest));
	    printf("/%s, next hop: ",inet_ntoa(c_eigrpr->netmask));
	    printf("%s\n",inet_ntoa(c_eigrpr->nexthop));
	    if (c_eigrpr->type==EIGRP_TYPE_EX_ROUTE) {
		printf("\t%13s%17s  "," ","external");
		printf("(%s,%lu,%lu,",inet_ntoa(c_eigrpr->origrouter),
			c_eigrpr->origas,c_eigrpr->externalmetric);
		switch (c_eigrpr->externallink) {
		    case 1:	printf("from IGRP)"); break;
		    case 2:	printf("from EIGRP)"); break;
		    case 3:	printf("from Static Routing)"); break;
		    case 4:	printf("from RIP)"); break;
		    case 5:	printf("from Hello)"); break;
		    case 6:	printf("from OSPF)"); break;
		    case 7:	printf("from IS-IS)"); break;
		    case 8:	printf("from EGP)"); break;
		    case 9:	printf("from BGP)"); break;
		    case 10:	printf("from IDRP)"); break;
		    case 11:	printf("Connected Link)"); break;
		    default:	printf("LINK UNKNOWN)"); 
		}
		printf("\n\t%32s"," ");
	    } else {
		printf("\t%13s%17s  "," ","internal");
	    }
	    //printf("\t%32s(%lu,%lu,%lu,%u,%u,%u)\n"," ",
	    printf("(%lu,%lu,%lu,%u,%u,%u)\n",
		    c_eigrpr->delay, c_eigrpr->bandwidth, c_eigrpr->mtu, 
		    c_eigrpr->reliability, c_eigrpr->load, c_eigrpr->hopcount);

	    c_eigrpr=c_eigrpr->next;
	}
	/* HSRP */
	c_hsrp=current->hsrp;
	while (c_hsrp!=NULL) {
	    printf("\tHSRP [%5u] %17s  (",
		    c_hsrp->group,inet_ntoa(c_hsrp->virtip));
	    switch (c_hsrp->state) {
		case HSRP_STATE_INITIAL:printf("Initial,"); break;
		case HSRP_STATE_LEARN:	printf("Learn,"); break;
		case HSRP_STATE_LISTEN:	printf("Listen,"); break;
		case HSRP_STATE_SPEAK:	printf("Speak,"); break;
		case HSRP_STATE_STANDBY:printf("Standby,"); break;
		case HSRP_STATE_ACTIVE:	printf("Active,"); break;
		default:		printf("Stat %u,",c_hsrp->state);
	    }
	    printf(" auth '%s',%u,%u,%u)\n",c_hsrp->auth,c_hsrp->hello,
		    c_hsrp->hold, c_hsrp->prio);
	    c_hsrp=c_hsrp->next;
	}
	/* OSPF */
	c_ospf=current->ospf;
	while (c_ospf!=NULL) {
	    printf("\tOSPF [ n/a ] %17s  (",inet_ntoa(c_ospf->source));
	    if (*((u_int32_t*)(&(c_ospf->area)))==0) {
		printf("Area: BACKBONE, ");
	    } else {
		printf("Area: %s, ",inet_ntoa(c_ospf->area));
	    } 
	    switch (c_ospf->authtype) {
		case 0:	printf("no auth,"); break;
		case 1:	printf("auth '%s',",c_ospf->authdata); break;
		case 2:	printf("crypto auth,"); break;
	    }
	    printf("\n\t%33s"," ");
	    printf("mask %s,",inet_ntoa(c_ospf->netmask));
	    printf("\n\t%33s"," ");
	    printf("Dsg: %s,",inet_ntoa(c_ospf->designated));
	    printf("\n\t%33s"," ");
	    printf("Bkp: %s,",inet_ntoa(c_ospf->backup));
	    printf("\n\t%33s"," ");
	    printf("Dead %lu, Prio %u, Hello %u)\n",
		    c_ospf->dead,c_ospf->prio,c_ospf->hello);

	    c_ospf=c_ospf->next;
	}

	current=current->next;
    }
}


void	clean_results(void) {
    result_t		*k,*current;
    RES_route_igrp_t	*k_igrp,*c_igrp;
    RES_route_irdp_t	*k_irdp,*c_irdp;
    RES_route_ripv1_t	*k_rip1,*c_rip1;
    RES_route_eigrp_t	*k_eigrp,*c_eigrp;
    RES_route_eigrprt_t	*k_eigrpr,*c_eigrpr;
    RES_route_hsrp_t	*k_hsrp,*c_hsrp;
    RES_route_ospf_t	*k_ospf,*c_ospf;
    RES_cdp_info_t	*k_cdp,*c_cdp;

    current=anchor;
    while (current!=NULL) {

	c_igrp=current->igrp;
	while (c_igrp!=NULL) {
	    k_igrp=c_igrp;
	    c_igrp=c_igrp->next;
	    free(k_igrp);
	}
	c_irdp=current->irdp;
	while (c_irdp!=NULL) {
	    k_irdp=c_irdp;
	    c_irdp=c_irdp->next;
	    free(k_irdp);
	}
	c_rip1=current->rip1;
	while (c_rip1!=NULL) {
	    k_rip1=c_rip1;
	    c_rip1=c_rip1->next;
	    free(k_rip1);
	}
	c_rip1=(RES_route_ripv1_t *)current->rip2;
	while (c_rip1!=NULL) {
	    k_rip1=c_rip1;
	    c_rip1=c_rip1->next;
	    free(k_rip1);
	}
	c_eigrp=current->eigrp;
	while (c_eigrp!=NULL) {
	    k_eigrp=c_eigrp;
	    c_eigrp=c_eigrp->next;
	    free(k_eigrp);
	}
	c_eigrpr=current->eigrpr;
	while (c_eigrpr!=NULL) {
	    k_eigrpr=c_eigrpr;
	    c_eigrpr=c_eigrpr->next;
	    free(k_eigrpr);
	}
	c_hsrp=current->hsrp;
	while (c_hsrp!=NULL) {
	    k_hsrp=c_hsrp;
	    c_hsrp=c_hsrp->next;
	    free(k_hsrp);
	}
	c_ospf=current->ospf;
	while (c_ospf!=NULL) {
	    k_ospf=c_ospf;
	    c_ospf=c_ospf->next;
	    free(k_ospf);
	}
	c_cdp=current->cdp;
	while (c_cdp!=NULL) {
	    k_cdp=c_cdp;
	    c_cdp=c_cdp->next;
	    if (k_cdp->deviceid!=NULL) free(k_cdp->deviceid);
	    if (k_cdp->portid!=NULL) free(k_cdp->portid);
	    if (k_cdp->software!=NULL) free(k_cdp->software);
	    if (k_cdp->platform!=NULL) free(k_cdp->platform);
	    if (k_cdp->vtpmgmt!=NULL) free(k_cdp->vtpmgmt);
	    free(k_cdp);
	}

	k=current;
	current=current->next;
	free(k);
    }
}



