pscan.c
上传用户:jxr_002
上传日期:2007-01-05
资源大小:12k
文件大小:14k
源码类别:

扫描程序

开发平台:

Unix_Linux

  1. /*
  2.  * pscan.c
  3.  *
  4.  *   TCP/UDP/NIS/RPC scanner..
  5.  *     o scans TCP ports and prints the services running
  6.  *     o scans UDP ports and prints the services running (remote hosts only)
  7.  *     o dumps portmappers listing of RPC services
  8.  *     o prints available NIS maps 
  9.  *
  10.  *   UDP port scanning is kinda flakey.. but it works.. with the exception 
  11.  *   of on your own host (netstat -a for christs sake).. anyway.. here 
  12.  *   it is..
  13.  *
  14.  *                  - pluvius@dhp.com
  15.  *
  16.  * tested on SunOS 4.1.3_U1 and Linux 1.1.85
  17.  * Also tested on OSF/1, courtesy of IETF.
  18.  * compile: cc -o pscan -s pscan.c
  19.  *
  20.  * NOTE: when you do a NIS listing.. it MUST be the domain name that
  21.  *       you pass as the remote host.. otherwise this will not work.
  22.  *
  23.  * H* mods: use a normally refused TCP port to determine UDP RTT delay.
  24.  * Much faster, and prevents the target from logging opened connections.
  25.  * May behave oddly if some TCP ports are dropped by a filter, and doesn't
  26.  * work on solaris cuz ICMP is *not* delivered to connected-UDP sockets.
  27.  * See udp_scan.c in Satan for more info, and a solaris version that works
  28.  * but needs root.
  29.  *
  30.  * If only one port arg given, just hit that port and report state.
  31.  *
  32.  * Added settable connect() timeout for tcp scan, with appropriate errors.
  33.  * Useful for determining what TCP ports are being filtered out -- scan a
  34.  * known machine behind a packet filter, and anything that wasn't refused
  35.  * or open is being dropped.  Ping first to get an idea of the right
  36.  * timeout to use; otherwise defaults to 3 sec.
  37.  *
  38.  * -->
  39.  *   connect time outs is broke on linux.. ripped it out. <p.
  40.  *   also yanked the --wait command thingy
  41.  *
  42.  *
  43.  * TODO: fix domainname shit, maybe rip code from satan yp_chk
  44.  *
  45. */
  46. #include <stdio.h>
  47. #include <unistd.h>
  48. #include <netdb.h>
  49. #include <sys/socket.h>
  50. #include <sys/types.h>
  51. #include <netinet/in.h>
  52. #include <rpc/rpc.h>
  53. #include <rpc/xdr.h>
  54. #include <rpc/pmap_prot.h>
  55. #include <rpc/pmap_clnt.h>
  56. #include <rpcsvc/yp_prot.h>
  57. #include <rpcsvc/ypclnt.h>
  58. #include <errno.h>
  59. #include <signal.h>
  60. #include <setjmp.h>
  61. /* xxx: these are sometimes defined by .h files as below for getopt.  I'll
  62.    fix it later... */
  63. extern int errno;
  64. #ifndef BSD4_4
  65. extern char *sys_errlist[];
  66. #endif
  67. #ifndef INADDR_NONE
  68. #define INADDR_NONE 0xffffffff
  69. #endif
  70. #ifdef __GNU_LIBRARY__    /* this is part of the GNU C lib */
  71. #include <getopt.h>
  72. #else
  73. extern int optind;
  74. extern char *optarg;
  75. #endif
  76. #define DEFAULT_LOW_PORT 1
  77. #define DEFAULT_HIGH_PORT 10240
  78. #define RTT_PORT 3 /* for UDP-RTT hack */
  79. #define MAJOR_VERSION 1
  80. #define MINOR_VERSION 4
  81. static char sccsid[] = "@(#) pscan.c 1.4 (pluvius+hobbit) 04/15/95";
  82. typedef enum {
  83.    false,
  84.    true
  85. } my_bool;
  86. my_bool Single = false; /* use booleans for all if-ed vars */
  87. typedef enum {
  88.    s_none,
  89.    s_tcp,
  90.    s_udp,
  91.    s_rpc,
  92.    s_nis
  93. } scan_t;
  94. #ifdef __GNU_LIBRARY__
  95. static struct option long_options[] = {
  96.    {"tcp", 0, 0, 0},
  97.    {"udp", 0, 0, 0},
  98.    {"rpc", 0, 0, 0},
  99.    {"nis", 0, 0, 0},
  100.    {"help", 0, 0, 0},
  101.    {"version", 0, 0, 0},
  102.    {0,0,0,0}
  103. };
  104. #endif
  105. struct {
  106.    char    *alias;
  107.    char    *mapname;
  108.    my_bool  inuse;
  109. } yp_maps[] = {
  110.    {"passwd",    "passwd.byname", false},
  111.    {"group",     "group.byname", false},
  112.    {"networks",  "networks.byaddr", false},
  113.    {"hosts",     "hosts.byaddr", false},
  114.    {"protocols", "protocols.bynumber", false},
  115.    {"services",  "services.byname", false},
  116.    {"aliases",   "mail.aliases", false},
  117.    {"ethers",    "ethers.byname", false},
  118.    {NULL,        NULL, false}
  119. };
  120. scan_t scan_type;
  121. char remote_host[200];
  122. char remote_ip[20];
  123. char remote_domain[128];
  124. int low_port;
  125. int high_port;
  126. void print_version(s)
  127. {
  128.    fprintf(stderr,"%s version %d.%dn",s,MAJOR_VERSION,MINOR_VERSION);
  129.    exit(0);
  130. }
  131. void print_usage(s)
  132. {
  133.    fprintf(stderr,"usage %s: <scan type> <host> [low port] [high port]n",s);
  134.    fprintf(stderr,"where scan type is one of:n");
  135. #ifdef __GNU_LIBRARY__
  136.    fprintf(stderr,"   --tcp, -t       - TCP port scann");
  137.    fprintf(stderr,"   --udp, -u       - UDP port scann");
  138.    fprintf(stderr,"   --rpc, -r       - RPC service listn");
  139.    fprintf(stderr,"   --nis, -n       - NIS map listingn");
  140.    fprintf(stderr,"   --version, -v   - Print version informationn");
  141.    fprintf(stderr,"   --help, -h      - Print usage informationn");
  142. #else
  143.    fprintf(stderr,"   -t              - TCP port scann");
  144.    fprintf(stderr,"   -u              - UDP port scann");
  145.    fprintf(stderr,"   -r              - RPC service listn");
  146.    fprintf(stderr,"   -n              - NIS map listingn");
  147.    fprintf(stderr,"   -v              - Print version informationn");
  148.    fprintf(stderr,"   -h              - Print usage informationn");
  149. #endif
  150.    fprintf(stderr,"n");
  151.    exit(0);
  152. }
  153. /* XXX: document -d after it works, maybe make -u take an arg? */
  154. void get_args(n,v)
  155. int n;
  156. char *v[];
  157. {
  158.  int c;
  159.  int opt_ind;
  160.    memset (remote_domain, 0, 8);
  161.    scan_type = s_none;
  162.    while (true) {
  163. #ifdef __GNU_LIBRARY__
  164.       c = getopt_long(n,v,"turnhvd:",long_options,&opt_ind);
  165. #else
  166.       c = getopt(n,v,"turnhvd:");
  167. #endif
  168.       if (c == -1)
  169.          break;
  170.       switch(c) {
  171. #ifdef __GNU_LIBRARY__
  172.        case 0:
  173.          opt_ind++; /* index's are one less than the scan type */
  174.          if (opt_ind == 5)
  175.             print_usage(v[0]);
  176.          if (opt_ind == 6)
  177.             print_version(v[0]);
  178.          scan_type = opt_ind;
  179.          break;
  180. #endif
  181.        case 't':
  182.          scan_type = s_tcp;
  183.          break;
  184.        case 'u':
  185.          scan_type = s_udp;
  186.          break;
  187.        case 'r':
  188.          scan_type = s_rpc;
  189.          break;
  190.        case 'n':
  191.          scan_type = s_nis;
  192.          break;
  193.        case 'd':
  194.  strcpy (remote_domain, optarg);
  195.  break;
  196.        case 'v':
  197.          print_version(v[0]);
  198.          break;
  199.        case 'h':
  200.        case '?':
  201.          print_usage(v[0]);
  202.          break;
  203.       }
  204.    }
  205.    low_port = DEFAULT_LOW_PORT;
  206.    high_port = DEFAULT_HIGH_PORT;
  207.    for (opt_ind = 0;optind < n;optind++) {
  208.       switch(opt_ind++) {
  209.        case 0: /* remote host */
  210.          strncpy(remote_host,v[optind],199);
  211.          break;
  212.        case 1: /* low port */
  213.          low_port = atoi(v[optind]);
  214.  Single = true;
  215.          break;
  216.        case 2: /* high port */
  217.          high_port = atoi(v[optind]);
  218.  Single = false;
  219.          break;
  220.       }
  221.    }
  222.    if (Single)
  223. high_port = low_port;
  224.    if ((opt_ind == 0) || (scan_type == s_none)) {
  225.       fprintf(stderr,"error: you must specify a scan type and a hostn");
  226.       print_usage(v[0]);
  227.    }
  228. }
  229. void check_args()
  230. {
  231.  struct hostent *host;
  232.    host = gethostbyname(remote_host);
  233.    if (host == NULL) {
  234. #if 0
  235. /* this sscanf and related code crashes on sunos, beats the shit out of me why.
  236.    In any case, punt -- just check the arg's validity with inet_addr and copy
  237.    it directly. */
  238.     unsigned char a,b,c,d,n;
  239.     char addr[5];
  240.       /* hmm.. perhaps it was a dotted quad entered.. */
  241.       n = sscanf(remote_host,"%u.%u.%u.%u",&a,&b,&c,&d);
  242.       if (n != 4) {
  243.          fprintf(stderr,"error: host '%s' not foundn",remote_host);
  244.          exit(1);
  245.       }
  246.       addr[0] = a;
  247.       addr[1] = b;
  248.       addr[2] = c;
  249.       addr[3] = d;
  250.       host = gethostbyaddr(addr,4,AF_INET);
  251. #endif /* 0 */
  252. /* ... we'll do it this way instead. */
  253.       unsigned long n;
  254.       n = inet_addr(remote_host);
  255.       if (n == INADDR_NONE) {
  256.          fprintf(stderr,"error: host '%s' not foundn",remote_host);
  257.          exit(1);
  258.       }
  259.       strcpy (remote_ip, remote_host);
  260.       host = gethostbyaddr(remote_ip,4,AF_INET);
  261.       if (host == NULL) {
  262.          fprintf(stderr,"error: host '%s' not foundn",remote_host);
  263.          exit(1);
  264.       }
  265.    } else {  /* gethostbyname */
  266.       sprintf(remote_ip,"%u.%u.%u.%u",
  267.               (unsigned char) host->h_addr_list[0][0],
  268.               (unsigned char) host->h_addr_list[0][1],
  269.               (unsigned char) host->h_addr_list[0][2],
  270.               (unsigned char) host->h_addr_list[0][3]);
  271.    }
  272. }
  273. void print_args()
  274. {
  275.  static char *opt_table[] = {
  276.     "tcp","udp","rpc","nis"
  277.  };
  278.   if (!Single) {
  279.    fprintf(stdout,"scanning host %s's %s ports ",remote_host,
  280.           opt_table[scan_type-1]);
  281.    if (scan_type < 3) {
  282.       fprintf(stdout,"%d through %d",low_port,high_port);
  283.    }
  284.    fprintf(stdout,"n");
  285.   } /* single */
  286. }
  287. void ping_host() 
  288. {
  289.  int s,slen;
  290.  struct sockaddr_in addr;
  291.  char out_string[100];
  292. /* What p. didn't explain here is that this is a simple way of delaying for
  293.    the expected RTT of the link, i.e. enough time for UDP out, ICMP back,
  294.    causing the next UDP write to error out.  Turns out that trying to connect
  295.    to a normally refused port is faster, although occasionally misses one. _H*/
  296.    /* send some stuff and wait for it to come back... ping for us */
  297.    /* non-root folks                                              */
  298.    s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  299.    addr.sin_family = AF_INET;
  300.    addr.sin_addr.s_addr = inet_addr(remote_ip);
  301.    addr.sin_port = htons(RTT_PORT);
  302.    /* timeout code didn't work on linux.. scrap it. <p. */
  303.    connect(s, (struct sockaddr*) &addr, sizeof(addr));
  304.    close(s);
  305. }
  306. int scan()
  307. {
  308.  int soc;
  309.  struct sockaddr_in addr;
  310.  struct servent *serv;
  311.  int port,rc,addr_len,opt;
  312.    if (scan_type >= 3) /* this proc only does tcp and udp */
  313.       return;
  314.    errno = 0;
  315.    for (port = low_port;port <= high_port;port++) {
  316.       if (scan_type == s_tcp) {
  317.          soc = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  318.       } else if (scan_type == s_udp) {
  319.          soc = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
  320.       } else 
  321.          return;
  322.       if (soc < 0) {
  323.          fprintf(stderr,"error: socket() failedn");
  324.          return;
  325.       }
  326.       /* this makes scan drop to a crawl on linux... */
  327.       /*rc = setsockopt(soc,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));*/
  328.       addr.sin_family = AF_INET;
  329.       addr.sin_addr.s_addr = inet_addr(remote_ip);
  330.       addr.sin_port = htons(port);
  331.       addr_len = sizeof(addr);
  332.       rc = connect(soc, (struct sockaddr*) &addr, addr_len);
  333.       if (scan_type == s_udp) {
  334.        char out_text[100];
  335.          strncpy(out_text,"k0ad kidz uv th3 WeRlD UN1t3n",99); 
  336.          rc = write(soc,out_text,strlen(out_text));
  337.          ping_host(); /* wait for icmp's */
  338.          rc = write(soc,out_text,strlen(out_text));
  339.       }
  340.       close(soc);
  341. /* for tcp, if anything other than refused, we want to know about it.  Always
  342.    print status for a single-port run. */
  343.       if (!Single)
  344.         if ((rc < 0) && (scan_type == s_tcp) && (errno == ECONNREFUSED))
  345.   continue;
  346.       if ((rc < 0) && (scan_type == s_udp))
  347. continue;
  348.       if (scan_type == s_tcp)
  349.          serv = getservbyport(htons(port),"tcp");
  350.       else if (scan_type == s_udp) {
  351.          serv = getservbyport(htons(port),"udp");
  352.  rc = 0; /* fake out below msg */
  353.       }
  354.       else 
  355.          return;
  356.       fprintf(stdout,"port %d (%s) %sn", port,
  357. (serv == NULL)?"UNKNOWN": serv->s_name,
  358. (rc == 0) ? "open" : sys_errlist[errno]);
  359.       fflush (stdout);
  360.    }
  361. }
  362. int callback_proc(is,ik,ikl,iv,ivl,id)
  363. int is;
  364. char *ik;
  365. int ikl;
  366. char *iv;
  367. int ivl;
  368. char *id;
  369. {
  370.    if (is != YP_TRUE)
  371.       return is;
  372.    return 0;
  373. }
  374. void nis_dump()
  375. {
  376.  int i,rc;
  377.  char *domainname;
  378.  char *map;
  379.  struct ypall_callback callback;
  380.    if (remote_domain[0])
  381. domainname = &remote_domain[0];
  382.    else
  383. domainname = &remote_host[0];
  384.    for (i = 0;yp_maps[i].mapname != NULL;i++) {
  385.       callback.foreach = callback_proc;
  386.       callback.data = NULL;
  387.       map = yp_maps[i].mapname;
  388.       rc = yp_all(domainname,map,&callback);
  389.       switch(rc) {
  390.        case 0:
  391.          printf("%-10.10s is availablen",yp_maps[i].alias);
  392.          break;
  393.        case YPERR_YPBIND:
  394.          fprintf(stderr,"error: server is not running ypbindn");
  395.          exit(1);
  396.          break;
  397.        default:
  398.          fprintf(stderr,"error: %s in domain %sn",
  399. yperr_string(rc), domainname);
  400.          exit(1);
  401.       }
  402.    }
  403. }
  404. /* this routine basically ripped from rpcinfo -p */
  405. void rpc_scan()
  406. {
  407. struct sockaddr_in server_addr;
  408. register struct hostent *hp;
  409. struct pmaplist *head = NULL;
  410. int socket = RPC_ANYSOCK;
  411. struct timeval minutetimeout;
  412. register CLIENT *client;
  413. struct rpcent *rpc;
  414. minutetimeout.tv_sec = 60;
  415. minutetimeout.tv_usec = 0;
  416.         server_addr.sin_addr.s_addr = inet_addr(remote_ip);
  417. server_addr.sin_family = AF_INET;
  418. server_addr.sin_port = htons(111);
  419. if ((client = clnttcp_create(&server_addr, PMAPPROG,
  420.     PMAPVERS, &socket, 50, 500)) == NULL) {
  421. clnt_pcreateerror("rpcinfo: can't contact portmapper");
  422. exit(1);
  423. }
  424. if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
  425.     xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
  426. fprintf(stderr, "rpcinfo: can't contact portmapper: ");
  427. clnt_perror(client, "rpcinfo");
  428. exit(1);
  429. }
  430. if (head == NULL) {
  431. printf("No remote programs registered.n");
  432. } else {
  433. printf("   program vers proto   portn");
  434. for (; head != NULL; head = head->pml_next) {
  435. printf("%10ld%5ld",
  436.     head->pml_map.pm_prog,
  437.     head->pml_map.pm_vers);
  438. if (head->pml_map.pm_prot == IPPROTO_UDP)
  439. printf("%6s",  "udp");
  440. else if (head->pml_map.pm_prot == IPPROTO_TCP)
  441. printf("%6s", "tcp");
  442. else
  443. printf("%6ld",  head->pml_map.pm_prot);
  444. printf("%7ld",  head->pml_map.pm_port);
  445. rpc = getrpcbynumber(head->pml_map.pm_prog);
  446. if (rpc)
  447. printf("  %sn", rpc->r_name);
  448. else
  449. printf("n");
  450. }
  451. }
  452. }
  453. int main(argc,argv)
  454. int argc;
  455. char *argv[];
  456. {
  457.    get_args(argc,argv);
  458.    check_args();
  459.    print_args();
  460.    /* this will only do tcp and udp, otherwise returns without doing anything */
  461.    switch (scan_type) {
  462.     case s_tcp:
  463.       scan();
  464.       break;
  465.     case s_udp:
  466.       scan();
  467.       break;
  468.     case s_rpc:
  469.       rpc_scan();
  470.       break;
  471.     case s_nis:
  472.       nis_dump();
  473.       break;
  474.    }
  475.    return 0;
  476. }