/*
 *	        	SyNsCaN - by psychoid
 *
 *             you need to be root for running this :P
 *             parts of the code are derived from sscan
 *     but it was buggy. i removed the bugs and got it working
 *
 *  Modified 2001-2004 by John Anderson and released under the GPL
 */


#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#ifdef LINUX
#include <linux/sockios.h>
#else
#ifndef HPUX
#include <sys/sockio.h>
#endif
#endif
#include <time.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <signal.h>

#include "synscan.h"
#include <pcap.h>
#include "localip.h"

#define TH_FIN  0x01
#define TH_SYN  0x02
#define TH_RST  0x04
#define TH_PUSH 0x08
#define TH_ACK  0x10
#define TH_URG  0x20

#define DEBUG_NET 0
#define DEBUG_PARSE 0
#define DEBUG_CHECKOS 0

#define ALARM_PCAP 2
#define ALARM_BLOCKING_IO 3

int tcpconnect (unsigned long sip, unsigned long ip, unsigned short port,
		unsigned short timeout, unsigned short iiport, char *param,
		FILE * output);

#define __BIG_ENDIAN_BITFIELD

void *telnet(unsigned long sip)
{
  int sockd;
  int count;
  struct sockaddr_in serv_name;
  unsigned char buf[100];
  char *ip;
  char saveip[256];
  char request[1024];
  char req_enc[6] = "\xff\xfd\x26\xff\xfb\x26";
  int status;
  FILE *f;

  sockd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockd == -1)
  {
    perror("Socket creation");
    return NULL;
  }

  serv_name.sin_family = AF_INET;
  serv_name.sin_addr.s_addr = sip;

  ip = inet_ntoa(serv_name.sin_addr);

  serv_name.sin_port = htons(23);
  unsigned long iMode = 1;

  status = connect(sockd, (struct sockaddr*)&serv_name, sizeof(serv_name));
  if (status == -1)
  {
        close(sockd);
        return NULL;
  }

  count = read(sockd, buf, 100);

  memcpy(request, req_enc, 6);
  write(sockd, request, 6);

  count = read(sockd, buf, 100);

  if (buf[0]==0xff&&buf[1]==0xfb&&buf[2]==0x26&&buf[3]==0xff&&buf[4]==0xfd&&buf[5]==0x26) {
        printf("\n%s supports encryption\n", ip);
        snprintf(saveip, sizeof(saveip), "%s\n", ip);
        f = fopen("scan.log", "a");
        fputs(saveip, f);
        fclose(f);

        close(sockd);
        return NULL;
  }

  close(sockd);
  return NULL;
}

int gpass = 0;
/*
int
checkpass ()
{
  char in[64];
  char good[64];
  bzero (good, sizeof (good));
  strcat (good, p1);
  strcat (good, p2);
  strcat (good, p3);
  strcat (good, p4);

  if (fgets (in, sizeof (in), stdin) == NULL)
    {
      kill (getpid (), 11);
      exit (0);
    }
  strcat (good, p5);
  strcat (good, p6);
  strcat (good, p7);
  strcat (good, p8);

  if (strncmp (in, good, 8) == 0)
    {
      return 1;
    }
  else
    {
      kill (getpid (), 11);
      exit (0);
    }

}
*/
struct tcphdr2
{
  uint16_t th_sport;		/* source port */
  uint16_t th_dport;		/* destination port */
  uint32_t th_seq;		/* sequence number */
  uint32_t th_ack;		/* acknowledgement number */
  /* swap these to for endian shit */
#ifdef LINUX
  uint8_t th_x2:4;		/* (unused) */
  uint8_t th_off:4;		/* data offset */

#else
  uint8_t th_off:4;		/* data offset */
  uint8_t th_x2:4;		/* (unused) */
#endif
  uint8_t th_flags;
  uint16_t th_win;		/* window */
  uint16_t th_sum;		/* checksum */
  uint16_t th_urp;		/* urgent pointer */
};

char deviceglobal[100];
u_long myip;
int iiport;
int eeport;			/* new - scanning to port */
int delay;
char outfilename[120];
char ircserver[200];

#ifndef LINUX
#define __BIG_ENDIAN_BITFIELD
struct iphdr
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
  uint8_t ihl:4, version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
  uint8_t version:4, ihl:4;
#else
#error  "Please fix <asm/byteorder.h>"
#endif
  uint8_t tos;
  uint16_t tot_len;
  uint16_t id;
  uint16_t frag_off;
  uint8_t ttl;
  uint8_t protocol;
  uint16_t check;
  uint32_t saddr;
  uint32_t daddr;
  /*The options start here. */
};
#endif

struct ifmap
{
  unsigned long mem_start;
  unsigned long mem_end;
  unsigned short base_addr;
  unsigned char irq;
  unsigned char dma;
  unsigned char port;
};

struct ifreq
{
#define IFHWADDRLEN	 6
#define IFNAMSIZ	 16
  union
  {
    char ifrn_name[IFNAMSIZ];
  } ifr_ifrn;

  union
  {
    struct sockaddr ifru_addr;
    struct sockaddr ifru_dstaddr;
    struct sockaddr ifru_broadaddr;
    struct sockaddr ifru_netmask;
    struct sockaddr ifru_hwaddr;
    short ifru_flags;
    int ifru_metric;
    int ifru_mtu;
    struct ifmap ifru_map;
    char ifru_slave[IFNAMSIZ];
    caddr_t ifru_data;
  } ifr_ifru;
};

#define ifr_name 	ifr_ifrn.ifrn_name
#define ifr_hwaddr 	ifr_ifru.ifru_hwaddr
#define ifr_addr	ifr_ifru.ifru_addr
#define ifr_dstaddr	ifr_ifru.ifru_dstaddr
#define ifr_broadaddr	ifr_ifru.ifru_broadaddr
#define ifr_netmask	ifr_ifru.ifru_netmask
#define ifr_flags	ifr_ifru.ifru_flags
#define ifr_metric	ifr_ifru.ifru_metric
#define ifr_mtu		ifr_ifru.ifru_mtu
#define ifr_map		ifr_ifru.ifru_map
#define ifr_slave	ifr_ifru.ifru_slave
#define ifr_data	ifr_ifru.ifru_data


struct ifconf
{
  int ifc_len;
  union
  {
    caddr_t ifcu_buf;
    struct ifreq *ifcu_req;

  } ifc_ifcu;
};

#define ifc_buf ifc_ifcu.ifcu_buf
#define ifc_req ifc_ifcu.ifcu_req

pcap_t *pcap_global_descriptor;
static int offset;

int
startpcap (void)
{
  char errbuf[1028];
  int datalink;
  struct pcap_pkthdr useless;
  if (!deviceglobal || !strcmp (deviceglobal, "default"))
    {
      strcpy (deviceglobal, pcap_lookupdev (errbuf));
    }
  if (!deviceglobal)
    {
      printf ("Error getting device - %s\n", errbuf);
      exit (1);
    }
  pcap_global_descriptor =
    pcap_open_live (deviceglobal, 10000, 0, 1000, errbuf);
  if (pcap_global_descriptor == NULL)
    {
      printf ("error opening pcap: %s\n", errbuf);
      printf ("Please enter a valid device (e.g. ppp0 or eth0\n");
      exit (1);
    }

  datalink = pcap_datalink (pcap_global_descriptor);
  bzero (&useless, sizeof (struct pcap_pkthdr));
  switch (datalink)
    {
    case DLT_EN10MB:
      offset = 14;
      break;
    case DLT_NULL:
    case DLT_PPP:
      offset = 4;
      break;
    case DLT_SLIP:
      offset = 16;
      break;
    case DLT_RAW:
      offset = 0;
      break;
    case DLT_SLIP_BSDOS:
    case DLT_PPP_BSDOS:
      offset = 24;
      break;
    case DLT_ATM_RFC1483:
      offset = 8;
      break;
    case DLT_IEEE802:
      offset = 22;
      break;
    default:
      fprintf (stderr, "unknown datalink type (%d)", datalink);
      return (0);
    }
  return 1;
}

void
endpcap (void)
{
  pcap_close (pcap_global_descriptor);
}

int
recvtcp (char *buf, int sizeofbuffer)
{
  char *ptr;
  struct pcap_pkthdr useless;

  struct tcppacket
  {
    struct iphdr ip;
    struct tcphdr2 tcp;
    u_char *data;

  } *tcppacket;

  tcppacket =
    (struct tcppacket *) pcap_next (pcap_global_descriptor, &useless);

  ptr = (char *) tcppacket;
  ptr += offset;
  tcppacket = (struct tcppacket *) ptr;

/* fprintf(stdout, "bleh %s\n", rlookup(LOCALIP)); */
/*
    fprintf(stdout,"Got Packet.. LEN: %d - FROM: %s - FROMPORT: %d - TOPORT: %d\n",
            tcppacket->ip.tot_len,rlookup(tcppacket->ip.saddr),
	    tcppacket->tcp.th_sport,tcppacket->tcp.th_dport);
*/
  if (gpass == 0)
    {
      bzero (buf, sizeof (buf));
    }
  if (ntohs (tcppacket->ip.tot_len) > sizeofbuffer - 1)
    return 0;
  memcpy (buf, tcppacket, ntohs (tcppacket->ip.tot_len));
  return 1;
}

#ifdef LINUX
u_long
getlocalip (void)
{
  int f, count, traverse;
  struct sockaddr_in *blob;
  char buf[512];
  struct ifreq *i;
  struct ifconf ic;
  f = socket (AF_INET, SOCK_STREAM, 0);
  ic.ifc_len = 512;
  ic.ifc_buf = buf;
  ioctl (f, SIOCGIFCONF, (char *) &ic);
  i = ic.ifc_req;
  count = ic.ifc_len / sizeof (struct ifreq);
  for (traverse = 0; traverse < count; traverse++)
    {
      ioctl (f, SIOCGIFADDR, (char *) &i);
      blob = (struct sockaddr_in *) &i->ifr_ifru.ifru_addr;
      if (!strcmp (i->ifr_name, deviceglobal))
	return blob->sin_addr.s_addr;
      i++;
    }
  return 0x0;
}
#else
u_long
getlocalip (void)
{
  return LOCALIP;
}
#endif

unsigned short
in_cksum (unsigned short *ptr, int nbytes)
{

  register long sum;
  u_short oddbyte;
  register u_short answer;

  sum = 0;
  while (nbytes > 1)
    {
      sum += *ptr++;
      nbytes -= 2;
    }

  if (nbytes == 1)
    {
      oddbyte = 0;
      *((u_char *) & oddbyte) = *(u_char *) ptr;
      sum += oddbyte;
    }

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

unsigned long int
lookup (char *hostname)
{
  struct hostent *name;
  unsigned long int address;

  if ((address = inet_addr (hostname)) != -1)
    return address;
  if ((name = gethostbyname (hostname)) == NULL)
    return -1;

  memcpy (&address, name->h_addr, name->h_length);
  return address;
}


int
checkvuln (unsigned long dest, int port, FILE * output)
{
  char param[4096];
  int sck;
  struct in_addr ami;

  memset (param, 0x0, sizeof (param));
  if (port == 23) {
	telnet(dest);
	return 0;
  }
  if (port == 111 || port == 80)
    {
      ami.s_addr = dest;
      fprintf (output, "%s(%s):%d :\n", inet_ntoa (ami), rlookup (dest),
	       port);
      sck = tcpconnect (dest, myip, 80, 10, port, outfilename, output);
      if (sck != -1)
	close (sck);
    }
  else
    {
      sck = tcpconnect (dest, myip, 80, 10, port, param, output);
      if (sck != -1)
	{
	  close (sck);
	  ami.s_addr = dest;
	  fprintf (output, "%s(%s):%d :%s\n", inet_ntoa (ami), rlookup (dest),
		   port, param);
	}
    }
  fflush (output);
  return 0;
}

int maxforq = 0;		// forkbombed

int
syn_portreceive (FILE * outm)
{
  char readbuf[2048];
  int frk = 0;
  struct tcppacket
  {
    struct iphdr ip;
    struct tcphdr2 tcp;
    char data[2000];
  }
   *tcppacket;
  maxforq = 0;
  while (1)
    {
      bzero (readbuf, sizeof (readbuf));
      if (recvtcp (readbuf, 2000))
	{
	  tcppacket = (struct tcppacket *) readbuf;
	  if ((tcppacket->tcp.th_flags & TH_SYN)
	      && (tcppacket->tcp.th_flags & TH_ACK))
	    {
	      if (myip != tcppacket->ip.saddr)
		{
		  if (ntohs (tcppacket->tcp.th_dport) >= iiport
		      && ntohs (tcppacket->tcp.th_dport) <= eeport)
		    {
		      frk = fork ();
		      if (frk == 0)
			{
			  checkvuln (tcppacket->ip.saddr,
				     ntohs (tcppacket->tcp.th_dport), outm);
			  exit (0x0);
			}
		      else
			{
			  maxforq++;
			  if (maxforq > MAXFORK)
			    {
			      wait (NULL);	// waiting until the child died
			      maxforq--;
			    }
			}
		    }
		}
	    }
	  if (tcppacket->tcp.th_flags & TH_RST)
	    {
	    }
	}
    }
  return 0;
}

void
pcap_alarm_handler (int bleh)
{
}

int
main (int argc, char **argv)
{
  FILE *infile;
  FILE *outfile;
  FILE *logo;
  char ports[600];
  struct sigaction alarmaction;
  char *ept;
  char *upt;

  srand(time(NULL));
  bzero (&alarmaction, sizeof (struct sigaction));
  if ((logo = fopen ("synscan.asc", "r")) != NULL)
    {
// use ports.. no point allocating extra vars since the logo is already displayed before the ports are set
      while (!feof (logo))
	{
	  fgets (ports, sizeof (ports) - 1, logo);
	  if (feof (logo))
	    break;
	  printf ("%s", ports);
	}
      fclose (logo);
    }
  fprintf (stdout, "SynScan Daemon %s by MadMax & psychoid/tCl\n",
	   SYNSCAN_VERSION);
  fprintf (stdout, "%s\n\n", SPEC);
  if (argc < 3)
    {
      fprintf (stdout, "Usage: %s outfile device(=ppp0/eth0) port\n",
	       argv[0]);
      exit (0x0);
    }
  if (argv[3] != NULL)
    {
      iiport = atoi (argv[3]);
      eeport = iiport;
      upt = ports;
    }
  else
    {
      iiport = 111;
      *ports = 0;
    }
  snprintf (deviceglobal, sizeof (deviceglobal), "%s", argv[2]);
  if (!strcmp (deviceglobal, "lo"))
    {
      printf ("Why would you want to scan yourself? Never heard of netstat?\n");
      fflush (stdout);
      exit (1);
    }

  myip = getlocalip ();
  if (myip == 0)
    {
      fprintf (stdout, "No IP found for device %s\n", deviceglobal);
    }
  fprintf (stdout, "My IP : %s\n", nlookup (myip));
  fprintf (stdout, "Writing to %s.\n", argv[1]);
  fprintf (stdout, "Using %d forks\n", MAXFORK);
  snprintf (ircserver, sizeof (ircserver), "irc.stealth.net:5558");
  if ((infile = fopen ("ircd.txt", "r")) != NULL)
    {
      if (fgets (ircserver, sizeof (ircserver), infile))
	{
	  ept = strchr (ircserver, '\r');
	  if (ept == NULL)
	    ept = strchr (ircserver, '\n');
	  if (ept != NULL)
	    *ept = 0;
	}
      fclose (infile);
    }
  ept = NULL;
  snprintf (outfilename, sizeof (outfilename), "%s", argv[1]);
  alarmaction.sa_handler = pcap_alarm_handler;
  alarmaction.sa_flags = 0;
  sigaction (SIGALRM, &alarmaction, NULL);
  startpcap ();
  fprintf (stdout, "Waiting for traffic \n");
/*    gpass=checkpass(); */
  gpass = 1;
  if ((outfile = fopen (outfilename, "a")) == NULL)
    {
      fprintf (stdout, "Cannot open %s, aborting..\n", argv[1]);
    }
  syn_portreceive (outfile);
  fclose (outfile);
  return 0;
}
