/*
Program: Custom Scan
Program by: lockdown
Date: March 1, 2001

Compile: gcc `libnet-config --defines` cscan.c -o cscan `libnet-config --libs` -lpcap
This program has since been updated to use libnet and libpcap.  You can set any TCP flags you want but only half open SYN scans and variants work.  If you want to see how an OS responds to different flags I recomend using snort to see the responses.  If you feel inclined you can add support for NULL and FIN scans which only work against certain OS's like linux, closed ports give a response and open ports do not respond.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <libnet.h>
#include <time.h>
#include <sys/param.h>
#include <pcap.h>

/*amount of time to wait for a response in seconds*/
#define TIMEOUT 2

/*not defined in libnet-headers.h so I do it myself here...*/
#define TH_RS1 0x40
#define TH_RS2 0x80

int timeout=0;

int scan(int,unsigned long,int,unsigned long,int,struct pcap *,int);
void alarm_handler(int);
int useage(char *);

struct iph {
  u_char  ihl;
  u_char  tos;
  short   tot_len;
  u_short id;
  short   off;
  u_char  ttl;
  u_char  protocol;
  u_short check;
  u_long  saddr; 
  u_long  daddr;
};

/*ripped from tfn2k*/
struct tcphd
{
  unsigned short th_sport,th_dport;
  unsigned int seq,ack;
#if __BYTE_ORDER == __LITTLE_ENDIAN
  unsigned char x2:4, off:4;
#else
  unsigned char off:4, x2:4;
#endif
  unsigned char flag;
#define FIN 0x01
#define SYN 0x02
#define RST 0x04
#define PSH 0x08
#define ACK 0x10
#define URG 0x20
  unsigned short int win, sum, urp;
};

int main(int argc, char *argv[])
{

  int start=5,end=0,opt,flags=0,offset,tcp_socket,datalink;
  unsigned long srcip;
  char host[50],*port,*device,errbuf[PCAP_ERRBUF_SIZE];
  uint32_t localnet,netmask;
  struct pcap *pd;
  struct bpf_program fp;

  if(argc != 3 && argc != 5 && argc != 7 && argc !=9)
  {
    useage(argv[0]);
  }
  if(geteuid()!=0)
  {
    fprintf(stderr,"Must be root to open a raw socket!\n");
    exit(1);
  }/* if */

  srand(time(NULL) ^ getpid() ^ getgid());

/*getopt sucks and doesn't require an arg like it should and i don't feel like 
  writing my own because it's not that important.  Just don't be a moron and you
  won't have any problems. */
  while((opt = getopt(argc,argv,"t:h:s:e:"))!=EOF)
  {
    switch(opt)
    {
      case 't':
        if(strchr(optarg,'f')!='\0')
          flags= flags | TH_FIN;
        if(strchr(optarg,'s')!='\0')
          flags= flags | TH_SYN;
        if(strchr(optarg,'r')!='\0')
          flags= flags | TH_RST;
        if(strchr(optarg,'p')!='\0')
          flags= flags | TH_PUSH;
        if(strchr(optarg,'a')!='\0')
          flags= flags | TH_ACK;
        if(strchr(optarg,'u')!='\0')
          flags= flags | TH_URG;
        if(strchr(optarg,'x')!='\0')
          flags= flags | TH_RS1;
        if(strchr(optarg,'y')!='\0')
          flags= flags | TH_RS2;
          break;
      case 'h':
        strncpy(host,optarg,50);
        break;
      case 's':
        start =atoi(optarg);
        break;
      case 'e':
        end = atoi(optarg);
        break;
    }/*switch*/
  }/* while */

  if(start > end || start < 0 || start > 65535 || end < 0 || end > 65535)
  {
    start = 1;
    end = 1024;
  }

  /* libpcap setup stuff */
  if((device=pcap_lookupdev(errbuf))==NULL)
  {
    fprintf(stderr,"pcap_lookup: %s",errbuf);
    exit(1);
  }

  if((srcip=htonl(libnet_get_ipaddr(NULL,device,errbuf)))==-1)
  {
    fprintf(stderr,"libnet_get_ipaddr: %s",errbuf);
    exit(1);
  } 

  if((pd=pcap_open_live(device,8024,0,1000,errbuf))==NULL)
  {
    fprintf(stderr,"pcap_open_live: %s",errbuf);
    exit(1);
  }

  switch(pcap_datalink(pd))
  {
    case DLT_NULL: offset=4;break;
    case DLT_EN10MB:
    case DLT_EN3MB: offset=14;break;
    case DLT_RAW: offset=0;break;
    default:
      fprintf(stderr,"Device not supported\n");
      exit(1);
  }

  if(pcap_lookupnet(device,&localnet,&netmask,errbuf)<0)
  {
    fprintf(stderr,"pcap_lookupnet: %s",errbuf);
    exit(1);
  }

  if((datalink=pcap_datalink(pd))<0)
  {
    fprintf(stderr,"pcap_datalink: %s",errbuf);
    exit(1);
  }

  /* libnet setup stuff */
  if((tcp_socket = libnet_open_raw_sock(IPPROTO_RAW))<0)
  {
    fprintf(stderr,"ERROR: libnet_open_raw_sock\n");
    exit(1);
  }

  if(pcap_compile(pd,&fp,"ip",0,netmask)<0)
  {
    fprintf(stderr,"ERROR: pcap_compile\n");
    exit(1);
  }

  if(pcap_setfilter(pd,&fp)<0)
  {
    fprintf(stderr,"ERROR: pcap_setfilter\n");
    exit(1);
  }

  printf("Scanning: %s\tports: %d to %d\n",host,start,end);
  for(;start<=end;start++)
  {
    signal(SIGALRM,alarm_handler);
    if(scan(start,libnet_name_resolve(host,1),flags,srcip,tcp_socket,pd,
            offset)==1)
      printf("\t%d\t\tis open\n",start);
  }
  return(0);
}/* main */

int scan(int port,unsigned long host,int flags,unsigned long srcip,
         int tcp_socket,struct pcap *pd,int offset)
{
  int id,srcp,seq,ack,window;
  unsigned char *packet;
  u_char *ptr;
  struct pcap_pkthdr hdr;
  struct iph *ip;
  struct tcphd *tcph;
  struct in_addr sh,dh;

  id=rand();
  srcp=rand() % 65535;
  seq=rand();
  ack=rand();
  window=rand();

  libnet_init_packet(LIBNET_MAX_PACKET,&packet);

  libnet_build_ip(LIBNET_TCP_H, IPTOS_LOWDELAY | IPTOS_THROUGHPUT,id,0,48,
                  IPPROTO_TCP,srcip,host,NULL,0,packet);
  libnet_build_tcp(srcp,port,seq,ack,flags,window,0,NULL,0,packet+LIBNET_IP_H);
  if(libnet_do_checksum(packet,IPPROTO_TCP,LIBNET_TCP_H)==-1)
    printf("error in checksum\n");

  libnet_write_ip(tcp_socket,packet,LIBNET_IP_H + LIBNET_TCP_H);
  libnet_destroy_packet(&packet);
  timeout=0;
  alarm(TIMEOUT);
  while(1)
  {
    while((ptr=(u_char *)pcap_next(pd,&hdr))==NULL && timeout == 0);
    if(timeout == 1)
      return 0;
    ip=(struct iph *)(ptr +offset);
    sh.s_addr=ip->saddr;
    dh.s_addr=ip->daddr;
    if(ip->protocol == IPPROTO_TCP)
    {
      tcph=(struct tcphd *)(ptr + offset + sizeof(struct iph));
      if(port == ntohs(tcph->th_sport) && srcp == ntohs(tcph->th_dport))
      {
        /* SYN scan */
        if((flags & SYN) == SYN)
        {
          alarm(0);
          /*half open*/
          if(flags ==SYN && (tcph->flag & (SYN+ ACK)) == (SYN + ACK))
            return 1;
          /*SYN + any flag combo as long as it doesn't contain RST or ACK*/
          else if(((flags & (SYN+ACK))==SYN || (flags &(SYN+RST))==SYN) &&
                  ((tcph->flag & (SYN+ACK))==(SYN+ACK)))
            return 1;
          else
            return 0;
        }/*if*/
        /*SYN wasn't set so we show everything as closed*/
        return 0;
      }/*if*/
    }/*if*/
    if(timeout == 1)
      return 0;
  }/*while*/
  /*should never reach here*/
  exit(1);
}/*scan*/

void alarm_handler(int signal)
{
  alarm(0);
  timeout=1;
}/* alarm_handler */

int useage(char *name)
{
  fprintf(stderr,"Useage: %s -t <tcpflags> -h <host> -s <port> -e <port>\n",
          name);
  fprintf(stderr,"\t tcp flags to set:\n");
  fprintf(stderr,"\t\t don't set -t for NULL scan\n");
  fprintf(stderr,"\t\t f for fin\n");
  fprintf(stderr,"\t\t s for syn\n");
  fprintf(stderr,"\t\t r for rst\n");
  fprintf(stderr,"\t\t p for psh\n");
  fprintf(stderr,"\t\t a for ack\n");
  fprintf(stderr,"\t\t u for urg\n");
  fprintf(stderr,"\t\t x for reserved 1\n");
  fprintf(stderr,"\t\t y for reserved 2\n");
  fprintf(stderr,"\t host is name of host to scan\n");
  fprintf(stderr,"\t -s port is the starting port\n");
  fprintf(stderr,"\t -e port is the ending port\n");
  exit(1);
}/* useage */

