nc.c 7.9 KB

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