/*
 * WARNING: THIS PROGRAM IS A HACK, DO NOT USE IT AS AN EXAMPLE OF
 * GOOD CODING STYLE, OR YOUR DOG MAY BITE YOU.
 *
 * Argument should be the destination IP address.  A small UDP
 * datagram will be sent to that address.
 *
 * This program uses the RAW socket interface and therefore needs to
 * be run by root.
 *
 * Jeremy Elson, jelson@circlemud.org
 * November 24, 1997
 */


/* Total size in bytes of the IP datagram */
#define SIZE 188

/* Source IP address (make sure it matches your machine, or you'll end
   up accidentally forging the datagram... */
#define SOURCE_IP "128.231.128.246"

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/udp.h>

u_short in_cksum(register u_short *addr, register int len);


int main(int argc, char *argv[])
{
   int s, opt, packetlen, i;
   struct sockaddr_in sa;
   struct in_addr ad;

   struct ip outip;
   struct udphdr outudp;

   char outp[10240];
   char packet[1024];

   char *message = "This is a test UDP Broadcast from Jeremy Elson, x20349.  ";

   strcpy(outp, message);
   for (i = 0; i < 20; i++)
      strcat(outp, message);

   if (argc != 3) {
     fprintf(stderr, "usage: %s <target-ip> <port>\n", argv[0]);
     exit(1);
   }

   if ((s = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
      perror("Create socket");
      exit(1);
   }

  opt = 1;
  if (setsockopt(s,SOL_SOCKET, SO_BROADCAST, (char *) &opt, sizeof(opt)) < 0) {
    perror("SYSERR: setsockopt BROADCAST");
    exit(1);
  }

#if 0
  opt = 1;
  if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &opt, sizeof(opt)) < 0) {
    perror("SYSERR: setsockopt TTL");
    exit(1);
  } else {
    fprintf(stderr, "ttl set to %d\n", opt);
  }
#endif

  packetlen = sizeof(outip) + sizeof(outudp) + SIZE;

  memset(&outip, 0, sizeof(outip));
  outip.ip_v = IPVERSION;
  outip.ip_tos = 0;
  outip.ip_len = packetlen;
  outip.ip_hl = sizeof(outip) / 4;
  outip.ip_id = 0;
  outip.ip_off = 0;
  outip.ip_ttl = 254;
  outip.ip_src.s_addr = htonl(inet_addr(SOURCE_IP));
  outip.ip_dst.s_addr = htonl(inet_addr(argv[1]));
  outip.ip_p = IPPROTO_UDP;

  outip.ip_sum =
    in_cksum((u_short *)&outip, sizeof(outip));
  if (outip.ip_sum == 0)
    outip.ip_sum = 0xffff;
	
  outudp.uh_sport = htons(1028);
  outudp.uh_dport = atoi(argv[2]);
  outudp.uh_sum = 0x0;
  outudp.uh_ulen = sizeof(outudp) + SIZE;

  sa.sin_family = AF_INET;
  sa.sin_addr.s_addr = htonl(inet_addr(argv[1]));

  memcpy(packet, &outip, sizeof(outip));
  memcpy(packet + sizeof(outip), &outudp, sizeof(outudp));
  memcpy(packet + sizeof(outip) + sizeof(outudp), outp, SIZE);

  if (sendto(s, packet, packetlen, 0, (struct sockaddr *) &sa, sizeof(sa))<0)
    perror("sending packet"); 

  exit(0);
}




/*
 * Checksum routine for Internet Protocol family headers (C Version)
 */
u_short
in_cksum(register u_short *addr, register int len)
{
	register int nleft = len;
	register u_short *w = addr;
	register u_short answer;
	register int sum = 0;

	/*
	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
	 *  we add sequential 16 bit words to it, and at the end, fold
	 *  back all the carry bits from the top 16 bits into the lower
	 *  16 bits.
	 */
	while (nleft > 1)  {
		sum += *w++;
		nleft -= 2;
	}

	/* mop up an odd byte, if necessary */
	if (nleft == 1)
		sum += *(u_char *)w;

	/*
	 * add back carry outs from top 16 bits to low 16 bits
	 */
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
	sum += (sum >> 16);			/* add carry */
	answer = ~sum;				/* truncate to 16 bits */
	return (answer);
}
