nc.c 8.0 KB

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