Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: */ |
Erik Andersen | 7ab9c7e | 2000-05-12 19:41:47 +0000 | [diff] [blame] | 2 | /* nc: mini-netcat - built from the ground up for LRP |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 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 tarball for details. |
| 8 | */ |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 9 | |
Eric Andersen | cbe31da | 2001-02-20 06:14:08 +0000 | [diff] [blame] | 10 | #include "busybox.h" |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 11 | |
Mike Frysinger | 60a5c38 | 2005-05-06 04:45:38 +0000 | [diff] [blame] | 12 | static void timeout(int signum) |
| 13 | { |
| 14 | bb_error_msg_and_die("Timed out"); |
| 15 | } |
| 16 | |
Erik Andersen | 7ab9c7e | 2000-05-12 19:41:47 +0000 | [diff] [blame] | 17 | int nc_main(int argc, char **argv) |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 18 | { |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 19 | int do_listen = 0, lport = 0, delay = 0, wsecs = 0, execflag = 0, opt, |
| 20 | sfd = 0, cfd; |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 21 | struct sockaddr_in address; |
| 22 | struct hostent *hostinfo; |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 23 | fd_set readfds, testfds; |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 24 | char *infile = NULL; |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 25 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 26 | memset(&address, 0, sizeof(address)); |
| 27 | |
| 28 | if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { |
| 29 | while ((opt = getopt(argc, argv, "lp:" USE_NC_EXTRA("i:ew:f:"))) > 0) { |
| 30 | if (ENABLE_NC_SERVER && opt=='l') do_listen++; |
| 31 | else if (ENABLE_NC_SERVER && opt=='p') |
Glenn L McGrath | 036dbaa | 2004-01-17 05:03:31 +0000 | [diff] [blame] | 32 | lport = bb_lookup_port(optarg, "tcp", 0); |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 33 | else if (ENABLE_NC_EXTRA && opt=='w') wsecs = atoi(optarg); |
| 34 | else if (ENABLE_NC_EXTRA && opt=='i') delay = atoi(optarg); |
| 35 | else if (ENABLE_NC_EXTRA && opt=='f') infile = optarg; |
| 36 | else if (ENABLE_NC_EXTRA && opt=='e' && optind!=argc) { |
| 37 | execflag++; |
Matt Kraai | 1d70267 | 2001-02-07 04:09:23 +0000 | [diff] [blame] | 38 | break; |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 39 | } else bb_show_usage(); |
Matt Kraai | 1d70267 | 2001-02-07 04:09:23 +0000 | [diff] [blame] | 40 | } |
Erik Andersen | 5e1189e | 2000-04-15 16:34:54 +0000 | [diff] [blame] | 41 | } |
Eric Andersen | b6a44b8 | 1999-11-13 04:47:09 +0000 | [diff] [blame] | 42 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 43 | |
| 44 | // For listen or file we need zero arguments, dialout is 2. |
| 45 | // For exec we need at least one more argument at the end, more ok |
Matt Kraai | 1d70267 | 2001-02-07 04:09:23 +0000 | [diff] [blame] | 46 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 47 | opt = (do_listen || infile) ? 0 : 2 + execflag; |
| 48 | if (execflag ? argc-optind < opt : argc-optind!=opt || |
| 49 | (infile && do_listen)) |
| 50 | bb_show_usage(); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 51 | |
Mike Frysinger | 60a5c38 | 2005-05-06 04:45:38 +0000 | [diff] [blame] | 52 | if (wsecs) { |
| 53 | signal(SIGALRM, timeout); |
| 54 | alarm(wsecs); |
| 55 | } |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 56 | |
| 57 | if (infile) cfd = bb_xopen(infile, O_RDWR); |
| 58 | else { |
| 59 | opt = 1; |
| 60 | sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0); |
| 61 | fcntl(sfd, F_SETFD, FD_CLOEXEC); |
| 62 | setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); |
| 63 | address.sin_family = AF_INET; |
Mike Frysinger | 60a5c38 | 2005-05-06 04:45:38 +0000 | [diff] [blame] | 64 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 65 | // Set local port. |
Matt Kraai | 1d70267 | 2001-02-07 04:09:23 +0000 | [diff] [blame] | 66 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 67 | if (lport != 0) { |
| 68 | address.sin_port = lport; |
Matt Kraai | 1d70267 | 2001-02-07 04:09:23 +0000 | [diff] [blame] | 69 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 70 | bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address)); |
| 71 | } |
Matt Kraai | be9f44a | 2001-05-15 03:05:39 +0000 | [diff] [blame] | 72 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 73 | if (do_listen) { |
| 74 | socklen_t addrlen = sizeof(address); |
Matt Kraai | 1d70267 | 2001-02-07 04:09:23 +0000 | [diff] [blame] | 75 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 76 | bb_xlisten(sfd, do_listen); |
Matt Kraai | 1d70267 | 2001-02-07 04:09:23 +0000 | [diff] [blame] | 77 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 78 | // If we didn't specify a port number, query and print it to stderr. |
Matt Kraai | 1d70267 | 2001-02-07 04:09:23 +0000 | [diff] [blame] | 79 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 80 | if (!lport) { |
| 81 | socklen_t len = sizeof(address); |
| 82 | getsockname(sfd, &address, &len); |
| 83 | fdprintf(2, "%d\n", SWAP_BE16(address.sin_port)); |
| 84 | } |
| 85 | repeatyness: |
| 86 | if ((cfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) |
| 87 | bb_perror_msg_and_die("accept"); |
| 88 | |
| 89 | if (!execflag) close(sfd); |
| 90 | } else { |
| 91 | hostinfo = xgethostbyname(argv[optind]); |
| 92 | |
| 93 | address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; |
| 94 | address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0); |
| 95 | |
| 96 | if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) |
| 97 | bb_perror_msg_and_die("connect"); |
| 98 | cfd = sfd; |
| 99 | } |
Matt Kraai | 1d70267 | 2001-02-07 04:09:23 +0000 | [diff] [blame] | 100 | } |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 101 | |
Mike Frysinger | 60a5c38 | 2005-05-06 04:45:38 +0000 | [diff] [blame] | 102 | if (wsecs) { |
| 103 | alarm(0); |
| 104 | signal(SIGALRM, SIG_DFL); |
| 105 | } |
| 106 | |
Eric Andersen | 1323c94 | 2002-04-26 23:59:12 +0000 | [diff] [blame] | 107 | /* -e given? */ |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 108 | if (execflag) { |
| 109 | if(cfd) { |
| 110 | signal(SIGCHLD, SIG_IGN); |
| 111 | dup2(cfd, 0); |
| 112 | close(cfd); |
| 113 | } |
Mike Frysinger | 7dc7f40 | 2005-05-06 05:00:34 +0000 | [diff] [blame] | 114 | dup2(0, 1); |
| 115 | dup2(0, 2); |
Eric Andersen | 1323c94 | 2002-04-26 23:59:12 +0000 | [diff] [blame] | 116 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 117 | // With more than one -l, repeatedly act as server. |
| 118 | |
| 119 | if (do_listen>1 && vfork()) { |
| 120 | // This is a bit weird as cleanup goes, since we wind up with no |
| 121 | // stdin/stdout/stderr. But it's small and shouldn't hurt anything. |
| 122 | // We check for cfd == 0 above. |
| 123 | close(0); |
| 124 | close(1); |
| 125 | close(2); |
| 126 | |
| 127 | goto repeatyness; |
| 128 | } |
| 129 | execvp(argv[optind], argv+optind); |
| 130 | /* Don't print stuff or it will go over the wire.... */ |
| 131 | _exit(127); |
| 132 | } |
| 133 | |
| 134 | // Select loop copying stdin to cfd, and cfd to stdout. |
| 135 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 136 | FD_ZERO(&readfds); |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 137 | FD_SET(cfd, &readfds); |
Matt Kraai | bfa7967 | 2000-12-15 22:34:34 +0000 | [diff] [blame] | 138 | FD_SET(STDIN_FILENO, &readfds); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 139 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 140 | for (;;) { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 141 | int fd; |
Eric Andersen | 2ce1edc | 1999-10-12 15:42:48 +0000 | [diff] [blame] | 142 | int ofd; |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 143 | int nread; |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 144 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 145 | testfds = readfds; |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 146 | |
Matt Kraai | bfa7967 | 2000-12-15 22:34:34 +0000 | [diff] [blame] | 147 | if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0) |
Manuel Novoa III | cad5364 | 2003-03-19 09:13:01 +0000 | [diff] [blame] | 148 | bb_perror_msg_and_die("select"); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 149 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 150 | for (fd = 0; fd < FD_SETSIZE; fd++) { |
| 151 | if (FD_ISSET(fd, &testfds)) { |
Rob Landley | 5343747 | 2006-07-16 08:14:35 +0000 | [diff] [blame] | 152 | nread = safe_read(fd, bb_common_bufsiz1, |
| 153 | sizeof(bb_common_bufsiz1)); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 154 | |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 155 | if (fd == cfd) { |
Rob Landley | 5343747 | 2006-07-16 08:14:35 +0000 | [diff] [blame] | 156 | if (nread<1) exit(0); |
Matt Kraai | bfa7967 | 2000-12-15 22:34:34 +0000 | [diff] [blame] | 157 | ofd = STDOUT_FILENO; |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 158 | } else { |
Rob Landley | 5343747 | 2006-07-16 08:14:35 +0000 | [diff] [blame] | 159 | if (nread<1) { |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 160 | // Close outgoing half-connection so they get EOF, but |
| 161 | // leave incoming alone so we can see response. |
| 162 | shutdown(cfd, 1); |
Paul Fox | 7b71d74 | 2005-07-18 22:23:16 +0000 | [diff] [blame] | 163 | FD_CLR(STDIN_FILENO, &readfds); |
| 164 | } |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 165 | ofd = cfd; |
Eric Andersen | 2ce1edc | 1999-10-12 15:42:48 +0000 | [diff] [blame] | 166 | } |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 167 | |
Rob Landley | 5343747 | 2006-07-16 08:14:35 +0000 | [diff] [blame] | 168 | xwrite(ofd, bb_common_bufsiz1, nread); |
Rob Landley | 1cca948 | 2006-07-10 19:45:20 +0000 | [diff] [blame] | 169 | if (delay > 0) sleep(delay); |
Eric Andersen | 2ce1edc | 1999-10-12 15:42:48 +0000 | [diff] [blame] | 170 | } |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 171 | } |
| 172 | } |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 173 | } |