10f66f451Sopenharmony_ci/* netcat.c - Forward stdin/stdout to a file or network connection. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2007 Rob Landley <rob@landley.net> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * TODO: udp, ipv6, genericize for telnet/microcom/tail-f 60f66f451Sopenharmony_ci * fix -t, xconnect 70f66f451Sopenharmony_ci * netcat -L zombies 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciUSE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN)) 100f66f451Sopenharmony_ciUSE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tElL")"w#<1W#<1p#<1>65535q#<1s:f:46uU"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46U]", TOYFLAG_BIN)) 110f66f451Sopenharmony_ci 120f66f451Sopenharmony_ciconfig NETCAT 130f66f451Sopenharmony_ci bool "netcat" 140f66f451Sopenharmony_ci default y 150f66f451Sopenharmony_ci help 160f66f451Sopenharmony_ci usage: netcat [-46U] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME|COMMAND...} 170f66f451Sopenharmony_ci 180f66f451Sopenharmony_ci Forward stdin/stdout to a file or network connection. 190f66f451Sopenharmony_ci 200f66f451Sopenharmony_ci -4 Force IPv4 210f66f451Sopenharmony_ci -6 Force IPv6 220f66f451Sopenharmony_ci -f Use FILENAME (ala /dev/ttyS0) instead of network 230f66f451Sopenharmony_ci -p Local port number 240f66f451Sopenharmony_ci -q Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet 250f66f451Sopenharmony_ci -s Local source address 260f66f451Sopenharmony_ci -u Use UDP 270f66f451Sopenharmony_ci -U Use a UNIX domain socket 280f66f451Sopenharmony_ci -w SECONDS timeout to establish connection 290f66f451Sopenharmony_ci -W SECONDS timeout for more data on an idle connection 300f66f451Sopenharmony_ci 310f66f451Sopenharmony_ci Use "stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho" with 320f66f451Sopenharmony_ci netcat -f to connect to a serial port. 330f66f451Sopenharmony_ci 340f66f451Sopenharmony_ciconfig NETCAT_LISTEN 350f66f451Sopenharmony_ci bool "netcat server options (-let)" 360f66f451Sopenharmony_ci default y 370f66f451Sopenharmony_ci depends on NETCAT 380f66f451Sopenharmony_ci help 390f66f451Sopenharmony_ci usage: netcat [-tElL] 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_ci -l Listen for one incoming connection, then exit 420f66f451Sopenharmony_ci -L Listen and background each incoming connection (server mode) 430f66f451Sopenharmony_ci -t Allocate tty 440f66f451Sopenharmony_ci -E Forward stderr 450f66f451Sopenharmony_ci 460f66f451Sopenharmony_ci When listening the COMMAND line is executed as a child process to handle 470f66f451Sopenharmony_ci an incoming connection. With no COMMAND -l forwards the connection 480f66f451Sopenharmony_ci to stdin/stdout. If no -p specified, -l prints the port it bound to and 490f66f451Sopenharmony_ci backgrounds itself (returning immediately). 500f66f451Sopenharmony_ci 510f66f451Sopenharmony_ci For a quick-and-dirty server, try something like: 520f66f451Sopenharmony_ci netcat -s 127.0.0.1 -p 1234 -tL sh -l 530f66f451Sopenharmony_ci*/ 540f66f451Sopenharmony_ci 550f66f451Sopenharmony_ci#define FOR_netcat 560f66f451Sopenharmony_ci#include "toys.h" 570f66f451Sopenharmony_ci 580f66f451Sopenharmony_ciGLOBALS( 590f66f451Sopenharmony_ci char *f, *s; 600f66f451Sopenharmony_ci long q, p, W, w; 610f66f451Sopenharmony_ci) 620f66f451Sopenharmony_ci 630f66f451Sopenharmony_cistatic void timeout(int signum) 640f66f451Sopenharmony_ci{ 650f66f451Sopenharmony_ci if (TT.w) error_exit("Timeout"); 660f66f451Sopenharmony_ci xexit(); 670f66f451Sopenharmony_ci} 680f66f451Sopenharmony_ci 690f66f451Sopenharmony_cistatic void set_alarm(int seconds) 700f66f451Sopenharmony_ci{ 710f66f451Sopenharmony_ci xsignal(SIGALRM, seconds ? timeout : SIG_DFL); 720f66f451Sopenharmony_ci alarm(seconds); 730f66f451Sopenharmony_ci} 740f66f451Sopenharmony_ci 750f66f451Sopenharmony_ci// open AF_UNIX socket 760f66f451Sopenharmony_cistatic int usock(char *name, int type, int out) 770f66f451Sopenharmony_ci{ 780f66f451Sopenharmony_ci int sockfd; 790f66f451Sopenharmony_ci struct sockaddr_un sockaddr; 800f66f451Sopenharmony_ci 810f66f451Sopenharmony_ci memset(&sockaddr, 0, sizeof(struct sockaddr_un)); 820f66f451Sopenharmony_ci 830f66f451Sopenharmony_ci if (strlen(name) + 1 > sizeof(sockaddr.sun_path)) 840f66f451Sopenharmony_ci error_exit("socket path too long %s", name); 850f66f451Sopenharmony_ci strcpy(sockaddr.sun_path, name); 860f66f451Sopenharmony_ci sockaddr.sun_family = AF_UNIX; 870f66f451Sopenharmony_ci 880f66f451Sopenharmony_ci sockfd = xsocket(AF_UNIX, type, 0); 890f66f451Sopenharmony_ci (out?xconnect:xbind)(sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); 900f66f451Sopenharmony_ci 910f66f451Sopenharmony_ci return sockfd; 920f66f451Sopenharmony_ci} 930f66f451Sopenharmony_ci 940f66f451Sopenharmony_ci 950f66f451Sopenharmony_civoid netcat_main(void) 960f66f451Sopenharmony_ci{ 970f66f451Sopenharmony_ci int sockfd = -1, in1 = 0, in2 = 0, out1 = 1, out2 = 1, family = AF_UNSPEC, 980f66f451Sopenharmony_ci ll = FLAG(L)|FLAG(l), type = FLAG(u) ? SOCK_DGRAM : SOCK_STREAM; 990f66f451Sopenharmony_ci pid_t child; 1000f66f451Sopenharmony_ci 1010f66f451Sopenharmony_ci // Addjust idle and quit_delay to ms or -1 for no timeout 1020f66f451Sopenharmony_ci TT.W = TT.W ? TT.W*1000 : -1; 1030f66f451Sopenharmony_ci TT.q = TT.q ? TT.q*1000 : -1; 1040f66f451Sopenharmony_ci 1050f66f451Sopenharmony_ci xsignal(SIGCHLD, SIG_IGN); 1060f66f451Sopenharmony_ci set_alarm(TT.w); 1070f66f451Sopenharmony_ci 1080f66f451Sopenharmony_ci // The argument parsing logic can't make "<2" conditional on other 1090f66f451Sopenharmony_ci // arguments like -f and -l, so do it by hand here. 1100f66f451Sopenharmony_ci if (FLAG(f) ? toys.optc : (!ll && toys.optc!=(FLAG(U)?1:2))) 1110f66f451Sopenharmony_ci help_exit("bad argument count"); 1120f66f451Sopenharmony_ci 1130f66f451Sopenharmony_ci if (FLAG(4)) family = AF_INET; 1140f66f451Sopenharmony_ci else if (FLAG(6)) family = AF_INET6; 1150f66f451Sopenharmony_ci else if (FLAG(U)) family = AF_UNIX; 1160f66f451Sopenharmony_ci 1170f66f451Sopenharmony_ci if (TT.f) in1 = out2 = xopen(TT.f, O_RDWR); 1180f66f451Sopenharmony_ci else { 1190f66f451Sopenharmony_ci // Setup socket 1200f66f451Sopenharmony_ci if (!ll) { 1210f66f451Sopenharmony_ci if (FLAG(U)) sockfd = usock(toys.optargs[0], type, 1); 1220f66f451Sopenharmony_ci else sockfd = xconnectany(xgetaddrinfo(toys.optargs[0], toys.optargs[1], 1230f66f451Sopenharmony_ci family, type, 0, 0)); 1240f66f451Sopenharmony_ci 1250f66f451Sopenharmony_ci // We have a connection. Disarm timeout and start poll/send loop. 1260f66f451Sopenharmony_ci set_alarm(0); 1270f66f451Sopenharmony_ci in1 = out2 = sockfd; 1280f66f451Sopenharmony_ci pollinate(in1, in2, out1, out2, TT.W, TT.q); 1290f66f451Sopenharmony_ci } else { 1300f66f451Sopenharmony_ci // Listen for incoming connections 1310f66f451Sopenharmony_ci if (FLAG(U)) { 1320f66f451Sopenharmony_ci if (!FLAG(s)) error_exit("-s must be provided if using -U with -L/-l"); 1330f66f451Sopenharmony_ci sockfd = usock(TT.s, type, 0); 1340f66f451Sopenharmony_ci } else { 1350f66f451Sopenharmony_ci sprintf(toybuf, "%ld", TT.p); 1360f66f451Sopenharmony_ci sockfd = xbindany(xgetaddrinfo(TT.s, toybuf, family, type, 0, 0)); 1370f66f451Sopenharmony_ci } 1380f66f451Sopenharmony_ci 1390f66f451Sopenharmony_ci if (listen(sockfd, 5)) error_exit("listen"); 1400f66f451Sopenharmony_ci if (!TT.p && !FLAG(U)) { 1410f66f451Sopenharmony_ci struct sockaddr* address = (void*)toybuf; 1420f66f451Sopenharmony_ci socklen_t len = sizeof(struct sockaddr_storage); 1430f66f451Sopenharmony_ci short port_be; 1440f66f451Sopenharmony_ci 1450f66f451Sopenharmony_ci getsockname(sockfd, address, &len); 1460f66f451Sopenharmony_ci if (address->sa_family == AF_INET) 1470f66f451Sopenharmony_ci port_be = ((struct sockaddr_in*)address)->sin_port; 1480f66f451Sopenharmony_ci else if (address->sa_family == AF_INET6) 1490f66f451Sopenharmony_ci port_be = ((struct sockaddr_in6*)address)->sin6_port; 1500f66f451Sopenharmony_ci else perror_exit("getsockname: bad family"); 1510f66f451Sopenharmony_ci 1520f66f451Sopenharmony_ci dprintf(1, "%d\n", SWAP_BE16(port_be)); 1530f66f451Sopenharmony_ci // Return immediately if no -p and -Ll has arguments, so wrapper 1540f66f451Sopenharmony_ci // script can use port number. 1550f66f451Sopenharmony_ci if (CFG_TOYBOX_FORK && toys.optc && xfork()) goto cleanup; 1560f66f451Sopenharmony_ci } 1570f66f451Sopenharmony_ci 1580f66f451Sopenharmony_ci do { 1590f66f451Sopenharmony_ci child = 0; 1600f66f451Sopenharmony_ci in1 = out2 = accept(sockfd, 0, 0); 1610f66f451Sopenharmony_ci if (in1<0) perror_exit("accept"); 1620f66f451Sopenharmony_ci 1630f66f451Sopenharmony_ci // We have a connection. Disarm timeout. 1640f66f451Sopenharmony_ci set_alarm(0); 1650f66f451Sopenharmony_ci 1660f66f451Sopenharmony_ci if (toys.optc) { 1670f66f451Sopenharmony_ci // Do we need a tty? 1680f66f451Sopenharmony_ci 1690f66f451Sopenharmony_ci// TODO nommu, and -t only affects server mode...? Only do -t with optc 1700f66f451Sopenharmony_ci// if (CFG_TOYBOX_FORK && (toys.optflags&FLAG_t)) 1710f66f451Sopenharmony_ci// child = forkpty(&fdout, NULL, NULL, NULL); 1720f66f451Sopenharmony_ci// else 1730f66f451Sopenharmony_ci 1740f66f451Sopenharmony_ci // Do we need to fork and/or redirect for exec? 1750f66f451Sopenharmony_ci 1760f66f451Sopenharmony_ci// TODO xpopen_both() here? 1770f66f451Sopenharmony_ci 1780f66f451Sopenharmony_ci if (FLAG(L)) NOEXIT(child = XVFORK()); 1790f66f451Sopenharmony_ci if (child) { 1800f66f451Sopenharmony_ci close(in1); 1810f66f451Sopenharmony_ci continue; 1820f66f451Sopenharmony_ci } 1830f66f451Sopenharmony_ci close(sockfd); 1840f66f451Sopenharmony_ci dup2(in1, 0); 1850f66f451Sopenharmony_ci dup2(in1, 1); 1860f66f451Sopenharmony_ci if (FLAG(E)) dup2(in1, 2); 1870f66f451Sopenharmony_ci if (in1>2) close(in1); 1880f66f451Sopenharmony_ci xexec(toys.optargs); 1890f66f451Sopenharmony_ci } 1900f66f451Sopenharmony_ci 1910f66f451Sopenharmony_ci pollinate(in1, in2, out1, out2, TT.W, TT.q); 1920f66f451Sopenharmony_ci close(in1); 1930f66f451Sopenharmony_ci } while (!FLAG(l)); 1940f66f451Sopenharmony_ci } 1950f66f451Sopenharmony_ci } 1960f66f451Sopenharmony_ci 1970f66f451Sopenharmony_cicleanup: 1980f66f451Sopenharmony_ci if (CFG_TOYBOX_FREE) { 1990f66f451Sopenharmony_ci close(in1); 2000f66f451Sopenharmony_ci close(sockfd); 2010f66f451Sopenharmony_ci } 2020f66f451Sopenharmony_ci} 203