source: MondoRescue/branches/3.3/mindi-busybox/networking/pscan.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 5.1 KB
Line 
1/*
2 * Pscan is a mini port scanner implementation for busybox
3 *
4 * Copyright 2007 Tito Ragusa <farmatito@tiscali.it>
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */
8
9//usage:#define pscan_trivial_usage
10//usage: "[-cb] [-p MIN_PORT] [-P MAX_PORT] [-t TIMEOUT] [-T MIN_RTT] HOST"
11//usage:#define pscan_full_usage "\n\n"
12//usage: "Scan a host, print all open ports\n"
13//usage: "\n -c Show closed ports too"
14//usage: "\n -b Show blocked ports too"
15//usage: "\n -p Scan from this port (default 1)"
16//usage: "\n -P Scan up to this port (default 1024)"
17//usage: "\n -t Timeout (default 5000 ms)"
18//usage: "\n -T Minimum rtt (default 5 ms, increase for congested hosts)"
19
20#include "libbb.h"
21
22/* debugging */
23#ifdef DEBUG_PSCAN
24#define DMSG(...) bb_error_msg(__VA_ARGS__)
25#define DERR(...) bb_perror_msg(__VA_ARGS__)
26#else
27#define DMSG(...) ((void)0)
28#define DERR(...) ((void)0)
29#endif
30
31static const char *port_name(unsigned port)
32{
33 struct servent *server;
34
35 server = getservbyport(htons(port), NULL);
36 if (server)
37 return server->s_name;
38 return "unknown";
39}
40
41/* We don't expect to see 1000+ seconds delay, unsigned is enough */
42#define MONOTONIC_US() ((unsigned)monotonic_us())
43
44int pscan_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
45int pscan_main(int argc UNUSED_PARAM, char **argv)
46{
47 const char *opt_max_port = "1024"; /* -P: default max port */
48 const char *opt_min_port = "1"; /* -p: default min port */
49 const char *opt_timeout = "5000"; /* -t: default timeout in msec */
50 /* We estimate rtt and wait rtt*4 before concluding that port is
51 * totally blocked. min rtt of 5 ms may be too low if you are
52 * scanning an Internet host behind saturated/traffic shaped link.
53 * Rule of thumb: with min_rtt of N msec, scanning 1000 ports
54 * will take N seconds at absolute minimum */
55 const char *opt_min_rtt = "5"; /* -T: default min rtt in msec */
56 const char *result_str;
57 len_and_sockaddr *lsap;
58 int s;
59 unsigned opt;
60 unsigned port, max_port, nports;
61 unsigned closed_ports = 0;
62 unsigned open_ports = 0;
63 /* all in usec */
64 unsigned timeout;
65 unsigned min_rtt;
66 unsigned rtt_4;
67 unsigned start, diff;
68
69 opt_complementary = "=1"; /* exactly one non-option */
70 opt = getopt32(argv, "cbp:P:t:T:", &opt_min_port, &opt_max_port, &opt_timeout, &opt_min_rtt);
71 argv += optind;
72 max_port = xatou_range(opt_max_port, 1, 65535);
73 port = xatou_range(opt_min_port, 1, max_port);
74 nports = max_port - port + 1;
75 min_rtt = xatou_range(opt_min_rtt, 1, INT_MAX/1000 / 4) * 1000;
76 timeout = xatou_range(opt_timeout, 1, INT_MAX/1000 / 4) * 1000;
77 /* Initial rtt is BIG: */
78 rtt_4 = timeout;
79
80 DMSG("min_rtt %u timeout %u", min_rtt, timeout);
81
82 lsap = xhost2sockaddr(*argv, port);
83 printf("Scanning %s ports %u to %u\n Port\tProto\tState\tService\n",
84 *argv, port, max_port);
85
86 for (; port <= max_port; port++) {
87 DMSG("rtt %u", rtt_4);
88
89 /* The SOCK_STREAM socket type is implemented on the TCP/IP protocol. */
90 set_nport(&lsap->u.sa, htons(port));
91 s = xsocket(lsap->u.sa.sa_family, SOCK_STREAM, 0);
92 /* We need unblocking socket so we don't need to wait for ETIMEOUT. */
93 /* Nonblocking connect typically "fails" with errno == EINPROGRESS */
94 ndelay_on(s);
95
96 DMSG("connect to port %u", port);
97 result_str = NULL;
98 start = MONOTONIC_US();
99 if (connect(s, &lsap->u.sa, lsap->len) == 0) {
100 /* Unlikely, for me even localhost fails :) */
101 DMSG("connect succeeded");
102 goto open;
103 }
104 /* Check for untypical errors... */
105 if (errno != EAGAIN && errno != EINPROGRESS
106 && errno != ECONNREFUSED
107 ) {
108 bb_perror_nomsg_and_die();
109 }
110
111 diff = 0;
112 while (1) {
113 if (errno == ECONNREFUSED) {
114 if (opt & 1) /* -c: show closed too */
115 result_str = "closed";
116 closed_ports++;
117 break;
118 }
119 DERR("port %u errno %d @%u", port, errno, diff);
120
121 if (diff > rtt_4) {
122 if (opt & 2) /* -b: show blocked too */
123 result_str = "blocked";
124 break;
125 }
126 /* Can sleep (much) longer than specified delay.
127 * We check rtt BEFORE we usleep, otherwise
128 * on localhost we'll have no writes done (!)
129 * before we exceed (rather small) rtt */
130 usleep(rtt_4/8);
131 open:
132 diff = MONOTONIC_US() - start;
133 DMSG("write to port %u @%u", port, diff - start);
134 if (write(s, " ", 1) >= 0) { /* We were able to write to the socket */
135 open_ports++;
136 result_str = "open";
137 break;
138 }
139 }
140 DMSG("out of loop @%u", diff);
141 if (result_str)
142 printf("%5u" "\t" "tcp" "\t" "%s" "\t" "%s" "\n",
143 port, result_str, port_name(port));
144
145 /* Estimate new rtt - we don't want to wait entire timeout
146 * for each port. *4 allows for rise in net delay.
147 * We increase rtt quickly (rtt_4*4), decrease slowly
148 * (diff is at least rtt_4/8, *4 == rtt_4/2)
149 * because we don't want to accidentally miss ports. */
150 rtt_4 = diff * 4;
151 if (rtt_4 < min_rtt)
152 rtt_4 = min_rtt;
153 if (rtt_4 > timeout)
154 rtt_4 = timeout;
155 /* Clean up */
156 close(s);
157 }
158 if (ENABLE_FEATURE_CLEAN_UP) free(lsap);
159
160 printf("%u closed, %u open, %u timed out (or blocked) ports\n",
161 closed_ports,
162 open_ports,
163 nports - (closed_ports + open_ports));
164 return EXIT_SUCCESS;
165}
Note: See TracBrowser for help on using the repository browser.