nc.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * nc: mini-netcat - built from the ground up for LRP
  4. *
  5. * Copyright (C) 1998, 1999 Charles P. Wright
  6. * Copyright (C) 1998 Dave Cinege
  7. *
  8. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  9. */
  10. //config:config NC
  11. //config: bool "nc (11 kb)"
  12. //config: default y
  13. //config: help
  14. //config: A simple Unix utility which reads and writes data across network
  15. //config: connections.
  16. //config:
  17. //config:config NETCAT
  18. //config: bool "netcat (11 kb)"
  19. //config: default n
  20. //config: help
  21. //config: Alias to nc.
  22. //config:
  23. //config:config NC_SERVER
  24. //config: bool "Netcat server options (-l)"
  25. //config: default y
  26. //config: depends on NC || NETCAT
  27. //config: help
  28. //config: Allow netcat to act as a server.
  29. //config:
  30. //config:config NC_EXTRA
  31. //config: bool "Netcat extensions (-eiw and -f FILE)"
  32. //config: default y
  33. //config: depends on NC || NETCAT
  34. //config: help
  35. //config: Add -e (support for executing the rest of the command line after
  36. //config: making or receiving a successful connection), -i (delay interval for
  37. //config: lines sent), -w (timeout for initial connection).
  38. //config:
  39. //config:config NC_110_COMPAT
  40. //config: bool "Netcat 1.10 compatibility (+2.5k)"
  41. //config: default y
  42. //config: depends on NC || NETCAT
  43. //config: help
  44. //config: This option makes nc closely follow original nc-1.10.
  45. //config: The code is about 2.5k bigger. It enables
  46. //config: -s ADDR, -n, -u, -v, -o FILE, -z options, but loses
  47. //config: busybox-specific extensions: -f FILE.
  48. //applet:IF_NC(APPLET(nc, BB_DIR_USR_BIN, BB_SUID_DROP))
  49. // APPLET_ODDNAME:name main location suid_type help
  50. //applet:IF_NETCAT(APPLET_ODDNAME(netcat, nc, BB_DIR_USR_BIN, BB_SUID_DROP, nc))
  51. //kbuild:lib-$(CONFIG_NC) += nc.o
  52. //kbuild:lib-$(CONFIG_NETCAT) += nc.o
  53. #include "libbb.h"
  54. #include "common_bufsiz.h"
  55. #if ENABLE_NC_110_COMPAT
  56. # include "nc_bloaty.c"
  57. #else
  58. //usage:#if !ENABLE_NC_110_COMPAT
  59. //usage:
  60. //usage:#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA
  61. //usage:#define NC_OPTIONS_STR "\n"
  62. //usage:#else
  63. //usage:#define NC_OPTIONS_STR
  64. //usage:#endif
  65. //usage:
  66. //usage:#define nc_trivial_usage
  67. //usage: IF_NC_EXTRA("[-iN] [-wN] ")IF_NC_SERVER("[-l] [-p PORT] ")
  68. //usage: "["IF_NC_EXTRA("-f FILE|")"IPADDR PORT]"IF_NC_EXTRA(" [-e PROG]")
  69. //usage:#define nc_full_usage "\n\n"
  70. //usage: "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE")
  71. //usage: NC_OPTIONS_STR
  72. //usage: IF_NC_SERVER(
  73. //usage: "\n -l Listen mode, for inbound connects"
  74. //usage: IF_NC_EXTRA(
  75. //usage: "\n (use -ll with -e for persistent server)"
  76. //usage: )
  77. //usage: "\n -p PORT Local port"
  78. //usage: )
  79. //usage: IF_NC_EXTRA(
  80. //usage: "\n -w SEC Connect timeout"
  81. //usage: "\n -i SEC Delay interval for lines sent"
  82. //usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network"
  83. //usage: "\n -e PROG Run PROG after connect"
  84. //usage: )
  85. //usage:
  86. //usage:#define nc_notes_usage ""
  87. //usage: IF_NC_EXTRA(
  88. //usage: "To use netcat as a terminal emulator on a serial port:\n\n"
  89. //usage: "$ stty 115200 -F /dev/ttyS0\n"
  90. //usage: "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n"
  91. //usage: )
  92. //usage:
  93. //usage:#define nc_example_usage
  94. //usage: "$ nc foobar.somedomain.com 25\n"
  95. //usage: "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n"
  96. //usage: "help\n"
  97. //usage: "214-Commands supported:\n"
  98. //usage: "214- HELO EHLO MAIL RCPT DATA AUTH\n"
  99. //usage: "214 NOOP QUIT RSET HELP\n"
  100. //usage: "quit\n"
  101. //usage: "221 foobar closing connection\n"
  102. //usage:
  103. //usage:#endif
  104. /* Lots of small differences in features
  105. * when compared to "standard" nc
  106. */
  107. static void timeout(int signum UNUSED_PARAM)
  108. {
  109. bb_error_msg_and_die("timed out");
  110. }
  111. int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  112. int nc_main(int argc, char **argv)
  113. {
  114. /* sfd sits _here_ only because of "repeat" option (-l -l). */
  115. int sfd = sfd; /* for gcc */
  116. int cfd = 0;
  117. unsigned lport = 0;
  118. IF_NOT_NC_SERVER(const) unsigned do_listen = 0;
  119. IF_NOT_NC_EXTRA (const) unsigned wsecs = 0;
  120. IF_NOT_NC_EXTRA (const) unsigned delay = 0;
  121. IF_NOT_NC_EXTRA (const int execparam = 0;)
  122. IF_NC_EXTRA (char **execparam = NULL;)
  123. struct pollfd pfds[2];
  124. int opt; /* must be signed (getopt returns -1) */
  125. if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
  126. /* getopt32 is _almost_ usable:
  127. ** it cannot handle "... -e PROG -prog-opt" */
  128. while ((opt = getopt(argc, argv,
  129. "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0
  130. ) {
  131. if (ENABLE_NC_SERVER && opt == 'l')
  132. IF_NC_SERVER(do_listen++);
  133. else if (ENABLE_NC_SERVER && opt == 'p')
  134. IF_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0));
  135. else if (ENABLE_NC_EXTRA && opt == 'w')
  136. IF_NC_EXTRA( wsecs = xatou(optarg));
  137. else if (ENABLE_NC_EXTRA && opt == 'i')
  138. IF_NC_EXTRA( delay = xatou(optarg));
  139. else if (ENABLE_NC_EXTRA && opt == 'f')
  140. IF_NC_EXTRA( cfd = xopen(optarg, O_RDWR));
  141. else if (ENABLE_NC_EXTRA && opt == 'e' && optind <= argc) {
  142. /* We cannot just 'break'. We should let getopt finish.
  143. ** Or else we won't be able to find where
  144. ** 'host' and 'port' params are
  145. ** (think "nc -w 60 host port -e PROG"). */
  146. IF_NC_EXTRA(
  147. char **p;
  148. // +2: one for progname (optarg) and one for NULL
  149. execparam = xzalloc(sizeof(char*) * (argc - optind + 2));
  150. p = execparam;
  151. *p++ = optarg;
  152. while (optind < argc) {
  153. *p++ = argv[optind++];
  154. }
  155. )
  156. /* optind points to argv[argc] (NULL) now.
  157. ** FIXME: we assume that getopt will not count options
  158. ** possibly present on "-e PROG ARGS" and will not
  159. ** include them into final value of optind
  160. ** which is to be used ... */
  161. } else bb_show_usage();
  162. }
  163. argv += optind; /* ... here! */
  164. argc -= optind;
  165. // -l and -f don't mix
  166. if (do_listen && cfd) bb_show_usage();
  167. // File mode needs need zero arguments, listen mode needs zero or one,
  168. // client mode needs one or two
  169. if (cfd) {
  170. if (argc) bb_show_usage();
  171. } else if (do_listen) {
  172. if (argc > 1) bb_show_usage();
  173. } else {
  174. if (!argc || argc > 2) bb_show_usage();
  175. }
  176. } else {
  177. if (argc != 3) bb_show_usage();
  178. argc--;
  179. argv++;
  180. }
  181. if (wsecs) {
  182. signal(SIGALRM, timeout);
  183. alarm(wsecs);
  184. }
  185. if (!cfd) {
  186. if (do_listen) {
  187. sfd = create_and_bind_stream_or_die(argv[0], lport);
  188. xlisten(sfd, do_listen); /* can be > 1 */
  189. #if 0 /* nc-1.10 does not do this (without -v) */
  190. /* If we didn't specify a port number,
  191. * query and print it after listen() */
  192. if (!lport) {
  193. len_and_sockaddr lsa;
  194. lsa.len = LSA_SIZEOF_SA;
  195. getsockname(sfd, &lsa.u.sa, &lsa.len);
  196. lport = get_nport(&lsa.u.sa);
  197. fdprintf(2, "%d\n", ntohs(lport));
  198. }
  199. #endif
  200. close_on_exec_on(sfd);
  201. accept_again:
  202. cfd = accept(sfd, NULL, 0);
  203. if (cfd < 0)
  204. bb_perror_msg_and_die("accept");
  205. if (!execparam)
  206. close(sfd);
  207. } else {
  208. cfd = create_and_connect_stream_or_die(argv[0],
  209. argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0);
  210. }
  211. }
  212. if (wsecs) {
  213. alarm(0);
  214. /* Non-ignored signals revert to SIG_DFL on exec anyway */
  215. /*signal(SIGALRM, SIG_DFL);*/
  216. }
  217. /* -e given? */
  218. if (execparam) {
  219. pid_t pid;
  220. /* With more than one -l, repeatedly act as server */
  221. if (do_listen > 1 && (pid = xvfork()) != 0) {
  222. /* parent */
  223. /* prevent zombies */
  224. signal(SIGCHLD, SIG_IGN);
  225. close(cfd);
  226. goto accept_again;
  227. }
  228. /* child, or main thread if only one -l */
  229. xmove_fd(cfd, 0);
  230. xdup2(0, 1);
  231. /*xdup2(0, 2); - original nc 1.10 does this, we don't */
  232. IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
  233. IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);)
  234. }
  235. /* loop copying stdin to cfd, and cfd to stdout */
  236. pfds[0].fd = STDIN_FILENO;
  237. pfds[0].events = POLLIN;
  238. pfds[1].fd = cfd;
  239. pfds[1].events = POLLIN;
  240. #define iobuf bb_common_bufsiz1
  241. setup_common_bufsiz();
  242. for (;;) {
  243. int fdidx;
  244. int ofd;
  245. int nread;
  246. if (safe_poll(pfds, 2, -1) < 0)
  247. bb_perror_msg_and_die("poll");
  248. fdidx = 0;
  249. while (1) {
  250. if (pfds[fdidx].revents) {
  251. nread = safe_read(pfds[fdidx].fd, iobuf, COMMON_BUFSIZE);
  252. if (fdidx != 0) {
  253. if (nread < 1)
  254. exit(EXIT_SUCCESS);
  255. ofd = STDOUT_FILENO;
  256. } else {
  257. if (nread < 1) {
  258. /* Close outgoing half-connection so they get EOF,
  259. * but leave incoming alone so we can see response */
  260. shutdown(cfd, SHUT_WR);
  261. pfds[0].fd = -1;
  262. }
  263. ofd = cfd;
  264. }
  265. xwrite(ofd, iobuf, nread);
  266. if (delay > 0)
  267. sleep(delay);
  268. }
  269. if (fdidx == 1)
  270. break;
  271. fdidx++;
  272. }
  273. }
  274. }
  275. #endif