Skip to content

Commit

Permalink
netcat: add -o
Browse files Browse the repository at this point in the history
  • Loading branch information
landley committed May 17, 2024
1 parent 007d102 commit 9c3eb4b
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 19 deletions.
4 changes: 3 additions & 1 deletion lib/lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,9 @@ void xconnect(int fd, const struct sockaddr *sa, socklen_t len);
int xconnectany(struct addrinfo *ai);
int xbindany(struct addrinfo *ai);
int xpoll(struct pollfd *fds, int nfds, int timeout);
int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout);
int pollinate(int in1, int in2, int out1, int out2,
void (*callback)(int fd, void *buf, size_t len),
int timeout, int shutdown_timeout);
char *ntop(struct sockaddr *sa);
void xsendto(int sockfd, void *buf, size_t len, struct sockaddr *dest);
int xrecvwait(int fd, char *buf, int len, union socksaddr *sa, int timeout);
Expand Down
6 changes: 4 additions & 2 deletions lib/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ int xpoll(struct pollfd *fds, int nfds, int timeout)
// Loop forwarding data from in1 to out1 and in2 to out2, handling
// half-connection shutdown. timeouts return if no data for X ms.
// Returns 0: both closed, 1 shutdown_timeout, 2 timeout
int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_timeout)
int pollinate(int in1, int in2, int out1, int out2,
void (*callback)(int fd, void *buf, size_t len),
int timeout, int shutdown_timeout)
{
struct pollfd pollfds[2];
int i, pollcount = 2;
Expand All @@ -115,7 +117,7 @@ int pollinate(int in1, int in2, int out1, int out2, int timeout, int shutdown_ti
int len = read(pollfds[i].fd, libbuf, sizeof(libbuf));
if (len<1) pollfds[i].revents = POLLHUP;
else {
xwrite(i ? out2 : out1, libbuf, len);
callback(i ? out2 : out1, libbuf, len);
continue;
}
}
Expand Down
82 changes: 66 additions & 16 deletions toys/net/netcat.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
*
* Copyright 2007 Rob Landley <rob@landley.net>
*
* TODO: genericize for telnet/microcom/tail-f, fix -t
* TODO: genericize for telnet/microcom/tail-f, fix -t with login_tty()
USE_NETCAT(NEWTOY(netcat, "^tElLw#<1W#<1p#<1>65535q#<1s:f:46uUnvz[!tlL][!Lw][!Lu][!46U]", TOYFLAG_BIN))
USE_NETCAT(NEWTOY(netcat, "^tElLw#<1W#<1p#<1>65535q#<1o:s:f:46uUnz[!tlL][!Lw][!Lu][!46U]", TOYFLAG_BIN))
USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
config NETCAT
bool "netcat"
default y
help
usage: netcat [-46ELlntUu] [-pqWw #] [-s addr] {IPADDR PORTNUM|-f FILENAME|COMMAND...}
usage: netcat [-46ELlntUu] [-pqWw #] [-s addr] [-o FILE] {IPADDR PORTNUM|-f FILENAME|COMMAND...}
Forward stdin/stdout to a file or network connection.
Expand All @@ -22,11 +22,11 @@ config NETCAT
-L Listen and background each incoming connection (server mode)
-l Listen for one incoming connection, then exit
-n No DNS lookup
-o Hex dump to FILE (-o- writes hex only to stdout)
-p Local port number
-q Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet
-s Local source address
-t Allocate tty
-v Verbose
-u Use UDP
-U Use a UNIX domain socket
-W SECONDS timeout for more data on an idle connection
Expand All @@ -49,8 +49,11 @@ config NETCAT
#include "toys.h"

GLOBALS(
char *f, *s;
char *f, *s, *o;
long q, p, W, w;

unsigned ofd, olast, opos, ocount[2];
char obuf[16];
)

static void timeout(int signum)
Expand Down Expand Up @@ -78,14 +81,64 @@ static int usock(char *name, int type, int out)
return sockfd;
}

// Hex dump accumulated buffer data
void oflush(void)
{
char *s = toybuf;
unsigned *oc = TT.ocount+(TT.olast==1), uu;

if (!TT.opos) return;
s += sprintf(toybuf, "%c %08x", 60+2*(TT.olast==1), *oc);
for (uu = 0; uu<16; uu++) {
s += sprintf(s, uu<TT.opos ? " %02x" : " ", TT.obuf[uu]);
if (TT.obuf[uu]-32u>95) TT.obuf[uu] = '.';
}
dprintf(TT.ofd, "%s # %.*s\n", toybuf, TT.opos, TT.obuf);
*oc += TT.opos;
TT.opos = 0;
}

// Write data to output, and hex dump to -o if enabled.
void ohexwrite(int fd, void *buf, size_t len)
{
// Hex dump if -o specified. Output is always to fd 1, input != 1.
if (TT.ofd) {
int i = 0, j;

if (TT.olast != fd) oflush();
TT.olast = fd;

while (i<len) {
j = minof(16-TT.opos, len-i);
memcpy(TT.obuf+TT.opos, buf+i, j);
TT.opos += j;
i += j;
if (TT.opos == 16) oflush();
}

// Don't write data to stdout when -o goes to stdout.
if (TT.ofd==1 && fd==1) return;
}

// Pass along raw data
xwrite(fd, buf, len);
}

void netcat_main(void)
{
int sockfd = -1, in1 = 0, in2 = 0, out1 = 1, out2 = 1, family = AF_UNSPEC,
type = FLAG(u) ? SOCK_DGRAM : SOCK_STREAM;
socklen_t len;
pid_t child;

// Addjust idle and quit_delay to ms or -1 for no timeout
// -o - disables normal writes to stdout, just gives hex dump.
if (TT.o) {
if (!strcmp(TT.o, "-")) TT.ofd = 1;
else TT.ofd = xcreate(TT.o, O_CREAT|O_TRUNC|O_WRONLY, 0666);
sigatexit(oflush);
}

// Adjust idle and quit_delay to ms or -1 for no timeout
TT.W = TT.W ? TT.W*1000 : -1;
TT.q = TT.q ? TT.q*1000 : -1;

Expand All @@ -107,24 +160,21 @@ void netcat_main(void)
if (TT.f) {
in1 = out2 = xopen(TT.f, O_RDWR);
alarm(0);
pollinate(in1, in2, out1, out2, TT.W, TT.q);
pollinate(in1, in2, out1, out2, ohexwrite, TT.W, TT.q);
} else {
// Setup socket
if (!FLAG(l) && !FLAG(L)) {
char *host = toys.optargs[0];
char *port = toys.optargs[1];
if (FLAG(U)) sockfd = usock(host, type, 1);
else sockfd = xconnectany(xgetaddrinfo(host, port, family, type, 0, AI_NUMERICHOST*FLAG(n)));

if (FLAG(v)) printf("%s:%s [open]\n", host, port);
if (FLAG(U)) sockfd = usock(toys.optargs[0], type, 1);
else sockfd = xconnectany(xgetaddrinfo(toys.optargs[0], toys.optargs[1],
family, type, 0, AI_NUMERICHOST*FLAG(n)));

// Do not perform any I/O in zero mode
if (FLAG(z)) goto cleanup;

// We have a connection. Disarm timeout and start poll/send loop.
alarm(0);
in1 = out2 = sockfd;
pollinate(in1, in2, out1, out2, TT.W, TT.q);
pollinate(in1, in2, out1, out2, ohexwrite, TT.W, TT.q);
} else {
// Listen for incoming connections
if (FLAG(U)) {
Expand Down Expand Up @@ -155,7 +205,7 @@ void netcat_main(void)
}

do {
len = sizeof(struct sockaddr_storage);
len = sizeof(struct sockaddr_storage);
if (FLAG(u)) {
if (-1 == recvfrom(in1 = dup(sockfd), &child, 1, MSG_PEEK,
(void *)toybuf, &len)) perror_exit("recvfrom");
Expand Down Expand Up @@ -191,7 +241,7 @@ void netcat_main(void)

// Copy stdin/out
} else {
pollinate(in1, in2, out1, out2, TT.W, TT.q);
pollinate(in1, in2, out1, out2, ohexwrite, TT.W, TT.q);
close(in1);
}
} while (FLAG(L));
Expand Down

0 comments on commit 9c3eb4b

Please sign in to comment.