1 /* netcat.c - Forward stdin/stdout to a file or network connection. 2 * 3 * Copyright 2007 Rob Landley <rob (at) 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 61 static void timeout(int signum) 62 { 63 if (TT.w) error_exit("Timeout"); 64 xexit(); 65 } 66 67 static void set_alarm(int seconds) 68 { 69 xsignal(SIGALRM, seconds ? timeout : SIG_DFL); 70 alarm(seconds); 71 } 72 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