1 /* netcat.c - Forward stdin/stdout to a file or network connection.
2 *
3 * Copyright 2007 Rob Landley <rob@landley.net>
4 *
5 * TODO: udp, ipv6, genericize for telnet/microcom/tail-f
6 * fix -t, xconnect
7 * netcat -L zombies
8
9 USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
10 USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46u"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46]", TOYFLAG_BIN))
11
12 config NETCAT
13 bool "netcat"
14 default y
15 help
16 usage: netcat [-46] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}
17
18 Forward stdin/stdout to a file or network connection.
19
20 -4 Force IPv4
21 -6 Force IPv6
22 -f Use FILENAME (ala /dev/ttyS0) instead of network
23 -p Local port number
24 -q Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet
25 -s Local source address
26 -u Use UDP
27 -w SECONDS timeout to establish connection
28 -W SECONDS timeout for more data on an idle connection
29
30 Use "stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho" with
31 netcat -f to connect to a serial port.
32
33 config NETCAT_LISTEN
34 bool "netcat server options (-let)"
35 default y
36 depends on NETCAT
37 help
38 usage: netcat [-t] [-lL COMMAND...]
39
40 -l Listen for one incoming connection
41 -L Listen for multiple incoming connections (server mode)
42 -t Allocate tty (must come before -l or -L)
43
44 The command line after -l or -L is executed (as a child process) to handle
45 each incoming connection. If blank -l waits for a connection and forwards
46 it to stdin/stdout. If no -p specified, -l prints port it bound to and
47 backgrounds itself (returning immediately).
48
49 For a quick-and-dirty server, try something like:
50 netcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l
51 */
52
53 #define FOR_netcat
54 #include "toys.h"
55
56 GLOBALS(
57 char *f, *s;
58 long q, p, W, w;
59 )
60
timeout(int signum)61 static void timeout(int signum)
62 {
63 if (TT.w) error_exit("Timeout");
64 xexit();
65 }
66
set_alarm(int seconds)67 static void set_alarm(int seconds)
68 {
69 xsignal(SIGALRM, seconds ? timeout : SIG_DFL);
70 alarm(seconds);
71 }
72
netcat_main(void)73 void netcat_main(void)
74 {
75 int sockfd = -1, in1 = 0, in2 = 0, out1 = 1, out2 = 1;
76 int family = AF_UNSPEC, type = SOCK_STREAM;
77 pid_t child;
78
79 // Addjust idle and quit_delay to ms or -1 for no timeout
80 TT.W = TT.W ? TT.W*1000 : -1;
81 TT.q = TT.q ? TT.q*1000 : -1;
82
83 set_alarm(TT.w);
84
85 // The argument parsing logic can't make "<2" conditional on other
86 // arguments like -f and -l, so do it by hand here.
87 if ((toys.optflags&FLAG_f) ? toys.optc :
88 (!(toys.optflags&(FLAG_l|FLAG_L)) && toys.optc!=2))
89 help_exit("bad argument count");
90
91 if (toys.optflags&FLAG_4) family = AF_INET;
92 else if (toys.optflags&FLAG_6) family = AF_INET6;
93
94 if (toys.optflags&FLAG_u) type = SOCK_DGRAM;
95
96 if (TT.f) in1 = out2 = xopen(TT.f, O_RDWR);
97 else {
98 // Setup socket
99 if (!(toys.optflags&(FLAG_L|FLAG_l))) {
100 struct addrinfo *addr = xgetaddrinfo(toys.optargs[0], toys.optargs[1],
101 family, type, 0, 0);
102 sockfd = xconnect(addr);
103
104 // We have a connection. Disarm timeout.
105 set_alarm(0);
106
107 in1 = out2 = sockfd;
108
109 pollinate(in1, in2, out1, out2, TT.W, TT.q);
110 } else {
111 // Listen for incoming connections
112 struct sockaddr* address = (void*)toybuf;
113 socklen_t len = sizeof(struct sockaddr_storage);
114
115 sprintf(toybuf, "%ld", TT.p);
116 sockfd = xbind(xgetaddrinfo(TT.s, toybuf, family, type, 0, 0));
117
118 if (listen(sockfd, 5)) error_exit("listen");
119 if (!TT.p) {
120 short port_be;
121
122 getsockname(sockfd, address, &len);
123 if (address->sa_family == AF_INET)
124 port_be = ((struct sockaddr_in*)address)->sin_port;
125 else if (address->sa_family == AF_INET6)
126 port_be = ((struct sockaddr_in6*)address)->sin6_port;
127 else
128 perror_exit("getsockname: bad family");
129
130 printf("%d\n", SWAP_BE16(port_be));
131 fflush(stdout);
132 // Return immediately if no -p and -Ll has arguments, so wrapper
133 // script can use port number.
134 if (CFG_TOYBOX_FORK && toys.optc && xfork()) goto cleanup;
135 }
136
137 do {
138 child = 0;
139 in1 = out2 = accept(sockfd, (struct sockaddr *)address, &len);
140 if (in1<0) perror_exit("accept");
141
142 // We have a connection. Disarm timeout.
143 set_alarm(0);
144
145 if (toys.optc) {
146 // Do we need a tty?
147
148 // TODO nommu, and -t only affects server mode...? Only do -t with optc
149 // if (CFG_TOYBOX_FORK && (toys.optflags&FLAG_t))
150 // child = forkpty(&fdout, NULL, NULL, NULL);
151 // else
152
153 // Do we need to fork and/or redirect for exec?
154
155 if (toys.optflags&FLAG_L) NOEXIT(child = XVFORK());
156 if (child) {
157 close(in1);
158 continue;
159 }
160 dup2(in1, 0);
161 dup2(in1, 1);
162 if (toys.optflags&FLAG_L) dup2(in1, 2);
163 if (in1>2) close(in1);
164 xexec(toys.optargs);
165 }
166
167 pollinate(in1, in2, out1, out2, TT.W, TT.q);
168 close(in1);
169 } while (!(toys.optflags&FLAG_l));
170 }
171 }
172
173 cleanup:
174 if (CFG_TOYBOX_FREE) {
175 close(in1);
176 close(sockfd);
177 }
178 }
179