Hi,
The following patch for netcat, adds the capability to limit the data
transfer bandwidth with the flag '-B'.
For instance, the following command limits ssh traffic to 40KB/s:
ssh -oProxyCommand='./nc -B 40 %h %p' localhost cat /bsd >/dev/null
? nc
Index: nc.1
===================================================================
RCS file: /cvs/src/usr.bin/nc/nc.1,v
retrieving revision 1.82
diff -u -p -r1.82 nc.1
--- nc.1 9 Feb 2017 20:15:59 -0000 1.82
+++ nc.1 26 May 2017 12:55:27 -0000
@@ -34,6 +34,7 @@
.Sh SYNOPSIS
.Nm nc
.Op Fl 46cDdFhklNnrStUuvz
+.Op Fl B Ar bandwidth
.Op Fl C Ar certfile
.Op Fl e Ar name
.Op Fl H Ar hash
@@ -101,6 +102,9 @@ to use IPv4 addresses only.
Forces
.Nm
to use IPv6 addresses only.
+.It Fl B Ar bandwidth
+Throttles the data transfer so that bandwith usage is limited to
+the amount given in KB per second.
.It Fl C Ar certfile
Specifies the filename from which the public key part of the TLS
certificate is loaded, in PEM format.
Index: netcat.c
===================================================================
RCS file: /cvs/src/usr.bin/nc/netcat.c,v
retrieving revision 1.178
diff -u -p -r1.178 netcat.c
--- netcat.c 9 Mar 2017 13:58:00 -0000 1.178
+++ netcat.c 26 May 2017 12:55:28 -0000
@@ -60,9 +60,9 @@
#define PORT_MAX 65535
#define UNIX_DG_TMP_SOCKET_SIZE 19
-#define POLL_STDIN 0
-#define POLL_NETOUT 1
-#define POLL_NETIN 2
+#define POLL_NETOUT 0
+#define POLL_NETIN 1
+#define POLL_STDIN 2
#define POLL_STDOUT 3
#define BUFSIZE 16384
#define DEFAULT_CA_FILE "/etc/ssl/cert.pem"
@@ -96,6 +96,7 @@ int Oflag; /* TCP send buffer size *
int Sflag; /* TCP MD5 signature option */
int Tflag = -1; /* IP Type of Service */
int rtableid = -1;
+long Bflag; /* max bandwidth */
int usetls; /* use TLS */
char *Cflag; /* Public cert file */
@@ -113,6 +114,8 @@ char *portlist[PORT_MAX+1];
char *unix_dg_tmp_socket;
int ttl = -1;
int minttl = -1;
+double tokens = 0.0;
+time_t tokens_ts = 0;
void atelnet(int, unsigned char *, unsigned int);
void build_ports(char *);
@@ -165,7 +168,7 @@ main(int argc, char *argv[])
signal(SIGPIPE, SIG_IGN);
while ((ch = getopt(argc, argv,
- "46C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:R:rSs:T:tUuV:vw:X:x:z")) != -1) {
+ "46B:C:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:R:rSs:T:tUuV:vw:X:x:z")) != -1) {
switch (ch) {
case '4':
family = AF_INET;
@@ -186,6 +189,11 @@ main(int argc, char *argv[])
else
errx(1, "unsupported proxy protocol");
break;
+ case 'B':
+ Bflag = strtonum(optarg, 0, LONG_MAX, &errstr);
+ if (errstr)
+ errx(1, "bandwidth %s: %s", errstr,
optarg);
+ break;
case 'C':
Cflag = optarg;
break;
@@ -1049,22 +1057,38 @@ readwrite(int net_fd, struct tls *tls_ct
stdinbufpos == 0 && netinbufpos == 0)
return;
- /* help says -i is for "wait between lines sent". We read and
- * write arbitrary amounts of data, and we don't want to start
- * scanning for newlines, so this is as good as it gets */
- if (iflag)
- sleep(iflag);
-
- /* poll */
- num_fds = poll(pfd, 4, timeout);
-
- /* treat poll errors */
- if (num_fds == -1)
- err(1, "polling error");
-
- /* timeout happened */
- if (num_fds == 0)
- return;
+ if (Bflag) {
+ time_t now = time(NULL);
+ tokens += 1024.0 * Bflag * (now - tokens_ts);
+ if (tokens > 4 * 1024.0 * Bflag) /* burst for
4s or data are allowed */
+ tokens = 4 * 1024.0 * Bflag;
+ tokens_ts = now;
+ }
+ if (Bflag && tokens < 0) {
+ /* this depends on POLL_NETIN being equal to
POLL_NETOUT+1 */
+ num_fds = poll(pfd + POLL_NETOUT, 2, 250);
+
+ pfd[POLL_STDIN].revents = 0;
+ pfd[POLL_STDOUT].revents = 0;
+ }
+ else {
+ /* help says -i is for "wait between lines
sent". We read and
+ * write arbitrary amounts of data, and we
don't want to start
+ * scanning for newlines, so this is as good as
it gets */
+ if (iflag)
+ sleep(iflag);
+
+ /* poll */
+ num_fds = poll(pfd, 4, timeout);
+
+ /* timeout happened */
+ if (num_fds == 0)
+ return;
+ }
+
+ /* treat poll errors */
+ if (num_fds == -1)
+ err(1, "polling error");
/* treat socket error conditions */
for (n = 0; n < 4; n++) {
@@ -1111,6 +1135,8 @@ readwrite(int net_fd, struct tls *tls_ct
pfd[POLL_STDIN].events = POLLOUT;
else if (ret == 0 || ret == -1)
pfd[POLL_STDIN].fd = -1;
+ else if (Bflag)
+ tokens -= ret;
/* read something - poll net out */
if (stdinbufpos > 0)
pfd[POLL_NETOUT].events = POLLOUT;
@@ -1171,6 +1197,8 @@ readwrite(int net_fd, struct tls *tls_ct
pfd[POLL_STDOUT].events = POLLOUT;
else if (ret == -1)
pfd[POLL_STDOUT].fd = -1;
+ else if (Bflag)
+ tokens -= ret;
/* buffer empty - remove self from polling */
if (netinbufpos == 0)
pfd[POLL_STDOUT].events = 0;
@@ -1644,6 +1672,7 @@ help(void)
fprintf(stderr, "\tCommand Summary:\n\
\t-4 Use IPv4\n\
\t-6 Use IPv6\n\
+ \t-B bandwidth Limit network bandwidth usage (KB/s)\n\
\t-C certfile Public key file\n\
\t-c Use TLS\n\
\t-D Enable the debug socket option\n\
@@ -1687,8 +1716,8 @@ void
usage(int ret)
{
fprintf(stderr,
- "usage: nc [-46cDdFhklNnrStUuvz] [-C certfile] [-e name] "
- "[-H hash] [-I length]\n"
+ "usage: nc [-46cDdFhklNnrStUuvz] [-B bandwidth] "
+ "[-C certfile] [-e name] [-H hash] [-I length]\n"
"\t [-i interval] [-K keyfile] [-M ttl] [-m minttl] [-O
length]\n"
"\t [-o staplefile] [-P proxy_username] [-p source_port] "
"[-R CAfile]\n"