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