www.pudn.com > newscan.zip > newscan.c


 
/* http://www.cotse.com  Fear the swimming Elephant! */ 
 
/* 
 * Half open port scanner. Send SYNs, and look for a SYN-ACK. If you see one, 
 * the port is listening. 
 * 
 * The whole point is to evade TCP-wrapper software and other alarm systems 
 * which look for a fully established connection. Since this never establishes 
 * a connection, its existance isn't logged. 
 * 
 * Note, this can be detected by things like TCPdump, or other raw network 
 * monitors. 
 * 
 * Runs under SunOS 4.x with NIT. This is a proof-of-concept toy, not a 
 * production model. :-) 
 * 
 * Mike Neuman 
 * 12/7/93 
 * 
 * You can do whatever you want with this code as long as you leave this 
 * header intact. 
 * 
 * Contact information: 
 * 
 * Mike Neuman (mcn@EnGarde.com) 
 */ 
 
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#include  
#include  
#include  
 
/* RPC makes an rpcdump call, which may be logged by a secure portmapper. 
 * If you're paranoid and want to guess at rpc stuff, specify -r 
 */ 
 
main(argc,argv) 
int argc; 
char *argv[]; 
 
{ 
  struct sockaddr_in server; 
  struct servent *sp; 
  struct hostent *hp; 
  int c, s, count, userpc=1, sock=RPC_ANYSOCK, minport = 1, maxport = 6001; 
  struct pmaplist *head = NULL, *headp=NULL; 
  struct timeval timeout; 
  register CLIENT *client; 
  struct rpcent *rpc; 
  unsigned long addr; 
  char *hostp; 
  extern char *optarg; 
  extern int optind; 
 
 
  /* 1: Parse options, get host addr */ 
  while ((c = getopt(argc, argv, "rhm:M:")) != -1) 
    switch(c) { 
      case 'r': 
        userpc = 0; 
        break; 
      case 'm': 
        minport = atoi(optarg); 
        break; 
      case 'M': 
        maxport = atoi(optarg); 
        break; 
      case 'h': 
        usage(argv[0]); 
        exit(1); 
    } 
         
  if (optind != argc-1) { 
    usage(argv[0]); 
    exit(1); 
  } 
 
  if (minport > maxport || minport <= 0) { 
    fprintf(stderr, "ERROR: minport must be > 0 and <= maxport\n"); 
    usage(argv[0]); 
    exit(1); 
  } 
  hostp = argv[optind]; 
 
  if ((hp=gethostbyname(hostp))==NULL) { 
    addr = inet_addr(hostp); 
    if (addr == (u_long)-1) { 
      fprintf(stderr, "Unknown host '%s'\n", hostp); 
      usage(argv[0]); 
      exit(1); 
    } 
    bcopy(&server.sin_addr, &addr, 4); 
  } else { 
    bzero((char *)&server, sizeof server); 
    bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length); 
    server.sin_family=hp->h_addrtype; 
  } 
 
  printf("Connections established for host %s:\n",hostp); 
 
  /* 2: Call rpc and get its ports */ 
  head=NULL; 
  if (userpc) { 
    server.sin_port=htons(PMAPPORT); 
    timeout.tv_sec=10; 
    timeout.tv_usec=0; 
    if ((client = clnttcp_create(&server, PMAPPROG, 
                                 PMAPVERS, &sock, 50, 500))!=NULL) { 
      if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL, 
                    xdr_pmaplist, &head, timeout) != RPC_SUCCESS) 
        head=NULL; 
    } 
  } 
 
  /* 3: Try each port from minport - maxport */ 
  for (count=minport;count<=maxport;count++) { 
    printf("\r%6d",count); 
    fflush(stdout); 
    server.sin_port=count; 
    if (!fakeconnect(&server, hostp)) { 
      printf("\r   %4d tcp   ",count); 
      sp=getservbyport(count,"tcp"); 
      if (sp==NULL) { 
        switch(count) { 
          /* Put in known services not in /etc/services here */ 
          case 2000: printf("(Xnews)"); 
            break; 
          case 6000: printf("(X)"); 
            break; 
          default: 
            if (userpc) { 
              headp=head; 
              while (headp!=NULL) { 
                if (headp->pml_map.pm_prot!=IPPROTO_TCP) { 
                  headp=headp->pml_next; 
                  continue; 
                } 
                if (count!=headp->pml_map.pm_port) { 
                  headp=headp->pml_next; 
                  continue; 
                } 
                rpc = getrpcbynumber(headp->pml_map.pm_prog); 
                if (rpc) { 
                  printf("%-15s [rpc]", rpc->r_name); 
                  break; 
                } else { 
                  headp=headp->pml_next; 
                  continue; 
                } 
              } 
              if (rpc==NULL) 
                printf("                [rpc]"); 
            } else 
              printf("???\n"); 
            break; 
        } 
      } else 
        printf("%-15s",sp->s_name); 
      printf("\n"); 
    } 
  } 
  printf("\n"); 
  exit(0); 
} 
 
usage(prog) 
char *prog; 
{ 
  fprintf(stderr,"Usage: %s [-r] [-m minport] [-M maxport] host\n", prog); 
  fprintf(stderr,"Options:\n"); 
  fprintf(stderr,"-r       Don't use RPC for port info\n"); 
  fprintf(stderr,"-m port  Specify port number to start at (default 1)\n"); 
  fprintf(stderr,"-M port  Specify port number to end at   (default 6001)\n"); 
  return; 
} 
 
 
int scan_return(fd, iph, tcph) 
int fd; 
struct ip *iph; 
struct tcphdr *tcph; 
 
{ 
  char buf[8*1024], *bp, *bufstop, *cp, abuf[2048]; 
  int cc, done=0, retval=0; 
  struct nit_bufhdr *hdrp; 
  struct nit_iftime *ntp; 
  struct nit_ifdrops *ndp; 
  struct nit_iflen *nlp; 
  struct ether_header *ep; 
  u_short et; 
  register struct ip *ip; 
  struct tcphdr *tp; 
 
  while (!done) { 
    if ((cc=read(fd, buf, 8*1024)) >= 0) { 
      bp=buf; 
      bufstop = buf+cc; 
      while (bp < bufstop) { 
        cp = bp; 
         
        /* Get past NIT buffer */ 
        hdrp = (struct nit_bufhdr *)cp; 
        cp += sizeof(*hdrp); 
         
        /* get past NIT timer   */ 
        ntp = (struct nit_iftime *)cp; 
        cp += sizeof(*ntp); 
         
        /* get past the drops */ 
        ndp = (struct nit_ifdrops *)cp; 
        cp += sizeof(*ndp); 
 
        /* get past packet len  */ 
        nlp = (struct nit_iflen *)cp; 
        cp += sizeof(*nlp); 
 
        /* next snapshot        */ 
        bp += hdrp->nhb_totlen; 
 
        /* Okay, got the packet, make sure it's a SYN-ACK reply */ 
        ep = (struct ether_header *)cp; 
        et = ntohs(ep->ether_type); 
        if ( et >= ETHERTYPE_TRAIL && et < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) 
          continue; 
        cp += sizeof(struct ether_header); 
        nlp->nh_pktlen -= sizeof(struct ether_header); 
        if (et != ETHERTYPE_IP) continue; 
         
        /* It's: ethernet + IP */ 
 
        ip=(struct ip *)cp; 
        bcopy((char *)ip, (char *)abuf, nlp->nh_pktlen); /* Align */ 
        ip = (struct ip *)abuf; 
 
        if (ip->ip_p != IPPROTO_TCP) 
          continue; 
 
        /* It's ethernet + IP + TCP */ 
        if (ip->ip_src.s_addr != iph->ip_dst.s_addr) 
          continue; 
        if (ip->ip_dst.s_addr != iph->ip_src.s_addr) 
          continue; 
 
        /* It's ethernet + IP + TCP + from target + to us */ 
        cp+=sizeof(struct ip); 
        tp = (struct tcphdr *)cp; 
        if (tp->th_sport != tcph->th_dport) 
          continue; 
        if (tp->th_dport != tcph->th_sport) 
          continue; 
 
        /* It's ethernet + IP + TCP + from target + to us + ports right */ 
        if ((tp->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { 
          retval=0; 
          done=1; 
        } else { 
          retval=1; 
          done=1; 
        } 
        break; 
      } /* While (bpsin_family = AF_INET; 
    s_arp->sin_addr.s_addr = server->sin_addr.s_addr; 
 
    /* First, send junk to it to get an ARP entry */ 
    s_arp->sin_port = 9; 
    sendto(s, "blah", 4, 0, (struct sockaddr *)s_arp, 
           sizeof(struct sockaddr_in)); 
    s_arp = (struct sockaddr_in *)&arpreq.arp_ha; 
    s_arp->sin_family = AF_UNSPEC; 
 
    if (ioctl(s, SIOCGARP, &arpreq) < 0) { 
      perror("ioctl"); 
      close(s); 
      exit(1); 
    } 
 
    if (arpreq.arp_flags & ATF_COM) { 
      bcopy(arpreq.arp_ha.sa_data, &faddr, 6); 
    } else { 
      fprintf(stderr, "Can't find destination/router hardware address.\n"); 
      exit(1); 
    } 
    /* faddr and myaddr are now computed, create the ether header */ 
    bcopy(&faddr, &eh.ether_dhost, 6); 
    eh.ether_type = htons(ETHERTYPE_IP); 
    sa.sa_family = AF_UNSPEC; 
    bcopy((char *)&eh, (char *)sa.sa_data, sizeof(struct ether_header)); 
    ctl.len = sizeof(struct sockaddr); 
    ctl.buf = (char *)&sa; 
    bp = buf; 
 
    iph.ip_v = IPVERSION; 
    iph.ip_hl = 5; /* 20 octets--no options */ 
    iph.ip_tos = htons(0);   /* No special service */ 
    iph.ip_len = htons(40); 
    iph.ip_id = htons(27); /* "unique" identification */ 
    iph.ip_off = htons(0); 
    iph.ip_ttl = htons(60); 
    iph.ip_p = htons(IPPROTO_TCP); 
    iph.ip_dst.s_addr = server->sin_addr.s_addr; 
    gethostname(buf, 2048); 
    he = gethostbyname(buf); 
    bcopy((char *)he->h_addr, 
          (char *)&iph.ip_src.s_addr, 
          sizeof(iph.ip_src.s_addr)); 
    iph.ip_sum = 0; 
    iph.ip_sum = htons(in_cksum_c(&iph, (iph.ip_hl << 2))); 
    bcopy((char *)&iph, bp, sizeof(struct ip)); 
    bp += sizeof(struct ip); 
    oldbp = bp; 
    computed=1; 
  } /* if !computed */ 
  /* Set up the TCP header */ 
  bp = oldbp; 
  tcph.th_sport = 5894; /* Random number */ 
  tcph.th_dport = server->sin_port; 
  tcph.th_seq = 59595; /* Random number */ 
  tcph.th_ack = 0; 
  tcph.th_off = 5; 
  tcph.th_flags = TH_SYN; 
  tcph.th_win = 4096; 
  tcph.th_sum = 0; 
  /* Calculate the TCP checksum on the TCP pseudoheader*/ 
  pbp=pbuf; 
  bcopy((char *)&iph.ip_src.s_addr, pbp, 4); 
  pbp+=4; 
  bcopy((char *)&iph.ip_dst.s_addr, pbp, 4); 
  pbp+=4; 
  *pbp=0; 
  pbp++; 
  *pbp=(char)iph.ip_p; 
  pbp++; 
  *(u_short *)pbp=(u_short)sizeof(struct tcphdr); 
  pbp+=2; /* go past the u_short */ 
  bcopy((char *)&tcph, pbp, sizeof(struct tcphdr)); 
  pbp+=sizeof(struct tcphdr); 
  if ((pbp-pbuf)%2) { 
    *pbp=(char)0; 
    pbp++; 
  } 
  tcph.th_sum = htons(in_cksum_c(pbuf, (int)(pbp-pbuf))); 
 
  bcopy((char *)&tcph, bp, sizeof(struct tcphdr)); 
  bp += sizeof(struct tcphdr); 
 
  datah.len = (int)(bp-buf); 
  datah.buf = (char *)buf; 
 
  if (putmsg(fd, &ctl, &datah, 0) < 0) { 
    perror("putmsg (ctl)"); 
    switch(errno) { 
      case EAGAIN: fprintf(stderr,"EAGAIN\n");break; 
      case EBADF: fprintf(stderr,"Bad FD\n");break; 
      case EFAULT: fprintf(stderr,"Bad ctlptr or dataptr\n");break; 
      case EINTR: fprintf(stderr,"Signal caught\n");break; 
      case EINVAL: fprintf(stderr,"undefined flag\n");break; 
      case ENOSTR: fprintf(stderr,"No stream\n");break; 
      case ENXIO: fprintf(stderr,"hangup downstream\n");break; 
      case ERANGE: fprintf(stderr,"data size problem\n");break; 
    } 
    exit(1); 
  } 
  /* Now that we've sent the syn, scan all return packets for reply */ 
  if (!setjmp(env_buf)) { 
    signal(SIGALRM, handle_alarm, -1); 
    alarm(1); 
    retval=scan_return(fd, &iph, &tcph); 
    alarm(0); 
  } else retval=1; 
  return(retval); 
} 
 
int fakeconnect(server, servername) 
/* 
 * Fake the connection, return 1 on failure, 0 on success 
 */ 
struct sockaddr_in *server; 
char *servername; 
{ 
  static int if_fd = -1; 
  char *device=0; 
  u_long localnet; 
  u_long netmask; 
  int linktype; 
  char *lookup_device(); 
  void lookup_net(); 
 
  if (if_fd == -1) { 
    if (device==0) { 
      device = lookup_device(); 
      if (device == 0) 
        perror("can't find any interfaces"); 
    } 
    if_fd = initdevice(device, &linktype); 
    lookup_net(device, &localnet, &netmask); 
  } 
  return(send_packet(if_fd, server, servername, localnet, netmask)); 
} 
 
 
/* ====================== begin nasty NIT stuff ======================= */ 
 
 
/* Not all systems have IFF_LOOPBACK */ 
#ifdef IFF_LOOPBACK 
#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK) 
#else 
#define ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo0") == 0) 
#endif 
 
char *lookup_device() 
{ 
  struct ifreq ibuf[16], *ifrp, *ifend, *mp; 
  struct ifconf ifc; 
  int fd; 
  int minunit, n; 
  char *cp; 
  static char device[sizeof(ifrp->ifr_name)]; 
 
  fd = socket(AF_INET, SOCK_DGRAM, 0); 
  if (fd < 0) { 
    perror("newscan: socket"); 
    exit(1); 
  } 
  ifc.ifc_len = sizeof(ibuf); 
  ifc.ifc_buf = (caddr_t)ibuf; 
 
  if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || 
      ifc.ifc_len < sizeof(struct ifreq)) { 
    perror("newscan: SIOCGIFCONF: "); 
    exit(1); 
  } 
  ifrp = ibuf; 
  ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); 
 
  mp = 0; 
  minunit = 666; 
  while (ifrp < ifend) { 
    struct ifreq ifr; 
    /* 
     * Need a template to preserve address info that is 
     * used below to locate the next entry.  (Otherwise, 
     * SIOCGIFFLAGS stomps over it because the requests 
     * are returned in a union.) 
     */ 
    bcopy(ifrp->ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); 
    if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { 
      fprintf(stderr, "newscan: SIOCGIFFLAGS: "); 
      perror(ifrp->ifr_name); 
      exit(1); 
    } 
    if ((ifr.ifr_flags & IFF_UP) && !ISLOOPBACK(&ifr)) { 
      for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) 
        ; 
      n = atoi(cp); 
      if (n < minunit) { 
        minunit = n; 
        mp = ifrp; 
      } 
    } 
#if BSD >= 199006 
    n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); 
    if (n < sizeof(*ifrp)) 
      ++ifrp; 
    else 
      ifrp = (struct ifreq *)((char *)ifrp + n); 
#else 
    ++ifrp; 
#endif 
  } 
  close(fd); 
  if (mp == 0) 
    return (0); 
 
  (void)strcpy(device, mp->ifr_name); 
  return (device); 
} 
 
/* 
 * Get the netmask of an IP address.  This routine is used if 
 * SIOCGIFNETMASK doesn't work. 
 */ 
static u_long 
ipaddrtonetmask(addr) 
u_long addr; 
{ 
  char str[80]; 
 
  if (IN_CLASSA(addr)) 
    return (IN_CLASSA_NET); 
  if (IN_CLASSB(addr)) 
    return (IN_CLASSB_NET); 
  if (IN_CLASSC(addr)) 
    return (IN_CLASSC_NET); 
  sprintf(str,"unknown IP address class: %08X", addr); 
  perror(str); 
  /* NOTREACHED */ 
} 
 
void 
lookup_net(device, netp, maskp) 
char *device; 
u_long *netp; 
u_long *maskp; 
{ 
  int fd; 
  struct ifreq ifr; 
  struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; 
 
  /* Use data gram socket to get IP address. */ 
  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 
    perror("newscan: socket"); 
    exit(1); 
  } 
  (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 
  if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) { 
    /* 
     * This will fail if an IP address hasn't been assigned. 
     */ 
    *netp = 0; 
    *maskp = 0; 
    return; 
  } 
  *netp = sin->sin_addr.s_addr; 
  if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) 
    *maskp = 0; 
  else 
    *maskp = sin->sin_addr.s_addr; 
  if (*maskp == 0) 
    *maskp = ipaddrtonetmask(*netp); 
  *netp &= *maskp; 
  (void)close(fd); 
} 
 
u_long snaplen = 0; 
 
int 
initdevice(device,linktype) 
char *device; 
int *linktype; 
{ 
  struct strioctl si;             /* struct for ioctl() */ 
  struct timeval timeout;         /* timeout for ioctl() */ 
  struct ifreq ifr;               /* interface request struct */ 
  u_long if_flags;                /* modes for interface             */ 
  int  ret; 
  /*  int chunksize = (8*1024); */ 
  int chunksize = 0; 
  int if_fd; 
  char *dev = "/dev/nit"; 
  int nonblock; 
 
  struct ether_header eh; 
  struct ip iptest; 
  struct packetfilt pf; 
  register u_short *fwp = pf.Pf_Filter; 
  u_short ethoffset; 
  u_short ipoffset; 
  u_short masker = 255; 
 
  si.ic_timout = INFTIM; 
 
  /* Set up the Packet Filter */ 
  ethoffset=((u_int)&eh.ether_type-(u_int)&eh.ether_dhost)/(sizeof(u_short)); 
  ipoffset = 11; 
  *fwp++ = ENF_PUSHZERO; 
  *fwp++ = ENF_PUSHWORD + ethoffset; 
  *fwp++ = ENF_PUSHLIT; 
  *fwp++ = htons(ETHERTYPE_IP); 
  *fwp++ = ENF_COR; 
  *fwp++ = ENF_PUSHWORD + ipoffset; 
  *fwp++ = ENF_PUSHLIT; 
  *fwp++ = (u_short)255; 
  *fwp++ = ENF_AND; 
  *fwp++ = ENF_PUSHLIT; 
  *fwp++ = (u_short)6; 
  *fwp++ = ENF_COR; 
  *fwp++ = ENF_PUSHLIT; 
  *fwp++ = (u_short)1; 
 
  /* open /dev/nit Read/write */ 
  if ((if_fd = open(dev, O_RDWR)) < 0) { 
    (void) fprintf(stderr, "newscan: open: "); 
    perror(dev); 
    exit(-1); 
  } 
 
  /* arrange to get discrete messages from the STREAM and use NIT_BUF */ 
  ioctl(if_fd, I_SRDOPT, (char*)RMSGD); 
 
  /* it is important to have this stuff in the stream BEFORE! the nbuf */ 
  si.ic_cmd = NIOCSETF; 
  si.ic_len = sizeof(struct packetfilt); 
  si.ic_dp = (char*)&pf; 
  pf.Pf_FilterLen = fwp - &pf.Pf_Filter[0]; 
  if (ioctl(if_fd, I_PUSH, "pf")<0) { 
    perror("I_PUSH pf"); 
    fprintf(stderr,"No pf being used\n"); 
  } else { 
    if ((ioctl(if_fd, I_STR, (char*)&si)) < 0) { 
      perror("newscan: NIOCSETF"); 
      /* exit(-1); */ 
      fprintf(stderr,"No pf being used (or one already applied)\n"); 
    } 
  } 
 
  ioctl(if_fd, I_PUSH, "nbuf"); 
 
  /* set the timeout */ 
  timeout.tv_sec = 1; 
  timeout.tv_usec = 0; 
  si.ic_cmd = NIOCSTIME; 
  si.ic_len = sizeof(timeout); 
  si.ic_dp = (char*)&timeout; 
  if ((ret = ioctl(if_fd, I_STR, (char*)&si)) < 0) { 
    perror("newscan: NIOCSTIME"); 
    exit(-1); 
  } 
 
  /* set the chunksize */ 
  si.ic_cmd = NIOCSCHUNK; 
  si.ic_len = sizeof(chunksize); 
  si.ic_dp = (char*)&chunksize; 
  if ((ret = ioctl(if_fd, I_STR, (char*)&si)) < 0) { 
    perror("newscan: NIOCSCHUNK"); 
    exit(-1); 
  } 
 
  /* Set up the NIT device (bind it,set snapshot length etc) */ 
  /* bind the interface */ 
  strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); 
  ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = ' '; 
  si.ic_cmd = NIOCBIND; 
  si.ic_len = sizeof(ifr); 
  si.ic_dp = (char*)𝔦 
  if ((ret = ioctl(if_fd, I_STR, (char*)&si)) < 0) { 
    (void) fprintf(stderr, "newscan: NIOCBIND"); 
    perror(ifr.ifr_name); 
    exit(1); 
  } 
 
  /* set the snapshot length */ 
  si.ic_cmd = NIOCSSNAP; 
  si.ic_len = sizeof(snaplen); 
  si.ic_dp = (char*)&snaplen; 
  if ((ret = ioctl(if_fd, I_STR, (char*)&si)) < 0) { 
    perror("newscan: NIOCSSNAP"); 
    exit(1); 
  } 
 
  /* set the interface flags */ 
  si.ic_cmd = NIOCSFLAGS; 
  if_flags = NI_TIMESTAMP | NI_LEN | NI_DROPS; 
  if_flags |= NI_PROMISC; 
  si.ic_len = sizeof(if_flags); 
  si.ic_dp = (char*)&if_flags; 
  if ((ioctl(if_fd, I_STR, (char*)&si)) < 0) { 
    perror("newscan: NIOCSFLAGS"); 
    exit(1); 
  } 
 
  nonblock = 1; 
  ioctl(if_fd, FIONBIO,&nonblock); 
 
  ioctl(if_fd, I_FLUSH, (char*)FLUSHR); 
  /* 
   * NIT supports only ethernets. 
   */ 
  *linktype = 1; 
 
  return if_fd; 
}