Home | History | Annotate | Download | only in net
      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