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 filename)"
  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 and -ll.
  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_EXTRA(
  60. //usage: "\n -e PROG Run PROG after connect"
  61. //usage: IF_NC_SERVER(
  62. //usage: "\n -l Listen mode, for inbound connects"
  63. //usage: IF_NC_EXTRA(
  64. //usage: "\n (use -l twice with -e for persistent server)")
  65. //usage: "\n -p PORT Local port"
  66. //usage: )
  67. //usage: "\n -w SEC Timeout for connect"
  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: )
  71. //usage:
  72. //usage:#define nc_notes_usage ""
  73. //usage: IF_NC_EXTRA(
  74. //usage: "To use netcat as a terminal emulator on a serial port:\n\n"
  75. //usage: "$ stty 115200 -F /dev/ttyS0\n"
  76. //usage: "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n"
  77. //usage: )
  78. //usage:
  79. //usage:#define nc_example_usage
  80. //usage: "$ nc foobar.somedomain.com 25\n"
  81. //usage: "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n"
  82. //usage: "help\n"
  83. //usage: "214-Commands supported:\n"
  84. //usage: "214- HELO EHLO MAIL RCPT DATA AUTH\n"
  85. //usage: "214 NOOP QUIT RSET HELP\n"
  86. //usage: "quit\n"
  87. //usage: "221 foobar closing connection\n"
  88. //usage:
  89. //usage:#endif
  90. /* Lots of small differences in features
  91. * when compared to "standard" nc
  92. */
  93. static void timeout(int signum UNUSED_PARAM)
  94. {
  95. bb_error_msg_and_die("timed out");
  96. }
  97. int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  98. int nc_main(int argc, char **argv)
  99. {
  100. /* sfd sits _here_ only because of "repeat" option (-l -l). */
  101. int sfd = sfd; /* for gcc */
  102. int cfd = 0;
  103. unsigned lport = 0;
  104. IF_NOT_NC_SERVER(const) unsigned do_listen = 0;
  105. IF_NOT_NC_EXTRA (const) unsigned wsecs = 0;
  106. IF_NOT_NC_EXTRA (const) unsigned delay = 0;
  107. IF_NOT_NC_EXTRA (const int execparam = 0;)
  108. IF_NC_EXTRA (char **execparam = NULL;)
  109. fd_set readfds, testfds;
  110. int opt; /* must be signed (getopt returns -1) */
  111. if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
  112. /* getopt32 is _almost_ usable:
  113. ** it cannot handle "... -e PROG -prog-opt" */
  114. while ((opt = getopt(argc, argv,
  115. "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0
  116. ) {
  117. if (ENABLE_NC_SERVER && opt == 'l')
  118. IF_NC_SERVER(do_listen++);
  119. else if (ENABLE_NC_SERVER && opt == 'p')
  120. IF_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0));
  121. else if (ENABLE_NC_EXTRA && opt == 'w')
  122. IF_NC_EXTRA( wsecs = xatou(optarg));
  123. else if (ENABLE_NC_EXTRA && opt == 'i')
  124. IF_NC_EXTRA( delay = xatou(optarg));
  125. else if (ENABLE_NC_EXTRA && opt == 'f')
  126. IF_NC_EXTRA( cfd = xopen(optarg, O_RDWR));
  127. else if (ENABLE_NC_EXTRA && opt == 'e' && optind <= argc) {
  128. /* We cannot just 'break'. We should let getopt finish.
  129. ** Or else we won't be able to find where
  130. ** 'host' and 'port' params are
  131. ** (think "nc -w 60 host port -e PROG"). */
  132. IF_NC_EXTRA(
  133. char **p;
  134. // +2: one for progname (optarg) and one for NULL
  135. execparam = xzalloc(sizeof(char*) * (argc - optind + 2));
  136. p = execparam;
  137. *p++ = optarg;
  138. while (optind < argc) {
  139. *p++ = argv[optind++];
  140. }
  141. )
  142. /* optind points to argv[arvc] (NULL) now.
  143. ** FIXME: we assume that getopt will not count options
  144. ** possibly present on "-e PROG ARGS" and will not
  145. ** include them into final value of optind
  146. ** which is to be used ... */
  147. } else bb_show_usage();
  148. }
  149. argv += optind; /* ... here! */
  150. argc -= optind;
  151. // -l and -f don't mix
  152. if (do_listen && cfd) bb_show_usage();
  153. // File mode needs need zero arguments, listen mode needs zero or one,
  154. // client mode needs one or two
  155. if (cfd) {
  156. if (argc) bb_show_usage();
  157. } else if (do_listen) {
  158. if (argc > 1) bb_show_usage();
  159. } else {
  160. if (!argc || argc > 2) bb_show_usage();
  161. }
  162. } else {
  163. if (argc != 3) bb_show_usage();
  164. argc--;
  165. argv++;
  166. }
  167. if (wsecs) {
  168. signal(SIGALRM, timeout);
  169. alarm(wsecs);
  170. }
  171. if (!cfd) {
  172. if (do_listen) {
  173. sfd = create_and_bind_stream_or_die(argv[0], lport);
  174. xlisten(sfd, do_listen); /* can be > 1 */
  175. #if 0 /* nc-1.10 does not do this (without -v) */
  176. /* If we didn't specify a port number,
  177. * query and print it after listen() */
  178. if (!lport) {
  179. len_and_sockaddr lsa;
  180. lsa.len = LSA_SIZEOF_SA;
  181. getsockname(sfd, &lsa.u.sa, &lsa.len);
  182. lport = get_nport(&lsa.u.sa);
  183. fdprintf(2, "%d\n", ntohs(lport));
  184. }
  185. #endif
  186. close_on_exec_on(sfd);
  187. accept_again:
  188. cfd = accept(sfd, NULL, 0);
  189. if (cfd < 0)
  190. bb_perror_msg_and_die("accept");
  191. if (!execparam)
  192. close(sfd);
  193. } else {
  194. cfd = create_and_connect_stream_or_die(argv[0],
  195. argv[1] ? bb_lookup_port(argv[1], "tcp", 0) : 0);
  196. }
  197. }
  198. if (wsecs) {
  199. alarm(0);
  200. /* Non-ignored signals revert to SIG_DFL on exec anyway */
  201. /*signal(SIGALRM, SIG_DFL);*/
  202. }
  203. /* -e given? */
  204. if (execparam) {
  205. pid_t pid;
  206. /* With more than one -l, repeatedly act as server */
  207. if (do_listen > 1 && (pid = xvfork()) != 0) {
  208. /* parent */
  209. /* prevent zombies */
  210. signal(SIGCHLD, SIG_IGN);
  211. close(cfd);
  212. goto accept_again;
  213. }
  214. /* child, or main thread if only one -l */
  215. xmove_fd(cfd, 0);
  216. xdup2(0, 1);
  217. xdup2(0, 2);
  218. IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
  219. /* Don't print stuff or it will go over the wire... */
  220. _exit(127);
  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, 1);
  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