- single KERNEL_VERSION(a,b,c) macro in platform.h
[oweals/busybox.git] / networking / nc.c
1 /* vi: set sw=4 ts=4: */
2 /*  nc: mini-netcat - built from the ground up for LRP
3     Copyright (C) 1998  Charles P. Wright
4
5     0.0.1   6K      It works.
6     0.0.2   5K      Smaller and you can also check the exit condition if you wish.
7     0.0.3           Uses select()
8
9     19980918 Busy Boxed! Dave Cinege
10     19990512 Uses Select. Charles P. Wright
11     19990513 Fixes stdin stupidity and uses buffers.  Charles P. Wright
12
13     Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <signal.h>
21
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <netdb.h>
27 #include <sys/time.h>
28 #include <sys/ioctl.h>
29 #include "busybox.h"
30
31 static void timeout(int signum)
32 {
33         bb_error_msg_and_die("Timed out");
34 }
35
36 int nc_main(int argc, char **argv)
37 {
38         int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x;
39
40 #define buf bb_common_bufsiz1
41
42 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
43         char *pr00gie = NULL;
44 #endif
45
46         struct sockaddr_in address;
47         struct hostent *hostinfo;
48
49         fd_set readfds, testfds;
50
51         while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) {
52                 switch (opt) {
53                         case 'l':
54                                 do_listen++;
55                                 break;
56                         case 'p':
57                                 lport = bb_lookup_port(optarg, "tcp", 0);
58                                 break;
59                         case 'i':
60                                 delay = atoi(optarg);
61                                 break;
62 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
63                         case 'e':
64                                 pr00gie = optarg;
65                                 break;
66 #endif
67                         case 'w':
68                                 wsecs = atoi(optarg);
69                                 break;
70                         default:
71                                 bb_show_usage();
72                 }
73         }
74
75         if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
76                 bb_show_usage();
77
78         sfd = bb_xsocket(AF_INET, SOCK_STREAM, 0);
79         x = 1;
80         if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
81                 bb_perror_msg_and_die("reuseaddr");
82         address.sin_family = AF_INET;
83
84         if (wsecs) {
85                 signal(SIGALRM, timeout);
86                 alarm(wsecs);
87         }
88
89         if (lport != 0) {
90                 memset(&address.sin_addr, 0, sizeof(address.sin_addr));
91                 address.sin_port = lport;
92
93                 bb_xbind(sfd, (struct sockaddr *) &address, sizeof(address));
94         }
95
96         if (do_listen) {
97                 socklen_t addrlen = sizeof(address);
98
99                 bb_xlisten(sfd, 1);
100                 if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
101                         bb_perror_msg_and_die("accept");
102
103                 close(sfd);
104                 sfd = tmpfd;
105         } else {
106                 hostinfo = xgethostbyname(argv[optind]);
107
108                 address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
109                 address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
110
111                 if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
112                         bb_perror_msg_and_die("connect");
113         }
114
115         if (wsecs) {
116                 alarm(0);
117                 signal(SIGALRM, SIG_DFL);
118         }
119
120 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
121         /* -e given? */
122         if (pr00gie) {
123                 dup2(sfd, 0);
124                 close(sfd);
125                 dup2(0, 1);
126                 dup2(0, 2);
127                 execl(pr00gie, pr00gie, NULL);
128                 /* Don't print stuff or it will go over the wire.... */
129                 _exit(-1);
130         }
131 #endif /* CONFIG_NC_GAPING_SECURITY_HOLE */
132
133         FD_ZERO(&readfds);
134         FD_SET(sfd, &readfds);
135         FD_SET(STDIN_FILENO, &readfds);
136
137         while (1) {
138                 int fd;
139                 int ofd;
140                 int nread;
141
142                 testfds = readfds;
143
144                 if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0)
145                         bb_perror_msg_and_die("select");
146
147                 for (fd = 0; fd < FD_SETSIZE; fd++) {
148                         if (FD_ISSET(fd, &testfds)) {
149                                 if ((nread = safe_read(fd, buf, sizeof(buf))) < 0)
150                                         bb_perror_msg_and_die(bb_msg_read_error);
151
152                                 if (fd == sfd) {
153                                         if (nread == 0)
154                                                 exit(0);
155                                         ofd = STDOUT_FILENO;
156                                 } else {
157                                         if (nread <= 0) {
158                                                 shutdown(sfd, 1 /* send */ );
159                                                 close(STDIN_FILENO);
160                                                 FD_CLR(STDIN_FILENO, &readfds);
161                                         }
162                                         ofd = sfd;
163                                 }
164
165                                 if (bb_full_write(ofd, buf, nread) < 0)
166                                         bb_perror_msg_and_die(bb_msg_write_error);
167                                 if (delay > 0) {
168                                         sleep(delay);
169                                 }
170                         }
171                 }
172         }
173 }