Package: netcat-openbsd Version: 1.229-1 Severity: wishlist Tags: patch
Adds two Linux-specific flags:-B IP_BIND_ADDRESS_NO_PORT is used to allow binding to an address without specifying a port
-J Set both SO_REUSEPORT and SO_REUSEADDR on outgoing connections
From a21d62acfaab492bde82a25c678dc7cf7cf48f5c Mon Sep 17 00:00:00 2001 From: Adam F. Rogoyski <[email protected]> Date: Fri, 8 May 2026 23:01:40 -0700 Subject: [PATCH] Add -B (IP_BIND_ADDRESS_NO_PORT) and -J (SO_REUSEPORT on outbound bind) -B sets IP_BIND_ADDRESS_NO_PORT on the outbound socket before bind(2) when a source address or port is given with -s/-p, deferring source-port selection to connect(2). This lets the kernel pick a port lazily and share source ports across distinct 4-tuples, avoiding ephemeral-port exhaustion when many connections share a source address. IP_BIND_ADDRESS_NO_PORT is Linux-specific; the option is guarded by #ifdef and -B errors out at runtime on platforms that lack it, mirroring how -b handles SO_BROADCAST. -J sets SO_REUSEPORT and SO_REUSEADDR on the outbound socket before bind(2), allowing multiple processes to share the same local source (addr,port) on outbound connections, provided each connect(2) yields a unique 4-tuple. local_listen() already sets SO_REUSEPORT unconditionally for listen sockets, so -J only affects the connect path. The pair SO_REUSEADDR + SO_REUSEPORT mirrors what local_listen() does. The letters were chosen to avoid colliding with the TLS-enabled build: -R is reserved for the TLS root CA file (Rflag) when HAVE_TLS is set. Both -B and -J are unused in the HAVE_TLS and non-HAVE_TLS getopt strings. Forwarded: no --- nc.1 | 35 ++++++++++++++++++++++++++++++++++- netcat.c | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/nc.1 b/nc.1 index a159c73..45bc506 100644 --- a/nc.1 +++ b/nc.1 @@ -33,7 +33,7 @@ .Nd arbitrary TCP and UDP connections and listens .Sh SYNOPSIS .Nm nc -.Op Fl 46bCDdFhklNnrStUuvZz +.Op Fl 46BbCDdFhJklNnrStUuvZz .Op Fl I Ar length .Op Fl i Ar interval .Op Fl M Ar ttl @@ -93,6 +93,20 @@ The options are as follows: Use IPv4 addresses only. .It Fl 6 Use IPv6 addresses only. +.It Fl B +Set the +.Dv IP_BIND_ADDRESS_NO_PORT +socket option on outbound connections. +This defers source-port selection from +.Xr bind 2 +to +.Xr connect 2 , +allowing the kernel to share the source port across connections that +use the same source address but have distinct (remote address, remote port) +4-tuples. +Only takes effect when a source address is given with +.Fl s . +This option is Linux-specific. .It Fl b Allow broadcast. .It Fl C @@ -132,6 +146,25 @@ Sleep for .Ar interval seconds between lines of text sent and received. Also causes a delay time between connections to multiple ports. +.It Fl J +Set the +.Dv SO_REUSEPORT +and +.Dv SO_REUSEADDR +socket options on outbound connections before +.Xr bind 2 . +This allows multiple outbound sockets to share the same local +.Pq Fl s , Fl p +source address and port, provided each connection's full +4-tuple remains unique. +Only takes effect when a source address or port is given with +.Fl s +or +.Fl p . +For listen mode +.Pq Fl l , +.Dv SO_REUSEPORT +is always set and this flag is not required. .It Fl k When a connection is completed, listen for another one. Requires diff --git a/netcat.c b/netcat.c index 2a3714a..705005b 100644 --- a/netcat.c +++ b/netcat.c @@ -136,6 +136,7 @@ #define UDP_SCAN_TIMEOUT 3 /* Seconds */ /* Command Line Options */ +int Bflag; /* IP_BIND_ADDRESS_NO_PORT */ int bflag; /* Allow Broadcast */ int dflag; /* detached, no stdin */ int Fflag; /* fdpass sock to stdout */ @@ -157,6 +158,7 @@ int xflag; /* Socks proxy */ int zflag; /* Port Scan Flag */ int Dflag; /* sodebug */ int Iflag; /* TCP receive buffer size */ +int Jflag; /* SO_REUSEPORT on outbound bind */ int Oflag; /* TCP send buffer size */ int Sflag; /* TCP MD5 signature option */ int Tflag = -1; /* IP Type of Service */ @@ -270,9 +272,9 @@ main(int argc, char *argv[]) while ((ch = getopt(argc, argv, #ifdef HAVE_TLS - "46bC:cDde:FH:hI:i:K:klM:m:NnO:o:P:p:q:R:rSs:T:tUuV:vW:w:X:x:Z:z")) + "46BbC:cDde:FH:hI:i:JK:klM:m:NnO:o:P:p:q:R:rSs:T:tUuV:vW:w:X:x:Z:z")) #else - "46bCDdFhI:i:klM:m:NnO:P:p:q:rSs:T:tUuV:vW:w:X:x:Zz")) + "46BbCDdFhI:i:JklM:m:NnO:P:p:q:rSs:T:tUuV:vW:w:X:x:Zz")) #endif != -1) { switch (ch) { @@ -282,6 +284,13 @@ main(int argc, char *argv[]) case '6': family = AF_INET6; break; + case 'B': +#ifdef IP_BIND_ADDRESS_NO_PORT + Bflag = 1; +#else + errx(1, "no IP_BIND_ADDRESS_NO_PORT support available"); +#endif + break; case 'b': #ifdef SO_BROADCAST bflag = 1; @@ -338,6 +347,13 @@ main(int argc, char *argv[]) if (errstr) errx(1, "interval %s: %s", errstr, optarg); break; + case 'J': +#ifdef SO_REUSEPORT + Jflag = 1; +#else + errx(1, "no SO_REUSEPORT support available"); +#endif + break; #ifdef HAVE_TLS case 'K': Kflag = optarg; @@ -1229,6 +1245,21 @@ remote_connect(const char *host, const char *port, struct addrinfo hints, if ((error = getaddrinfo(sflag, pflag, &ahints, &ares))) errx(1, "getaddrinfo: %s", gai_strerror(error)); +#ifdef IP_BIND_ADDRESS_NO_PORT + if (Bflag && setsockopt(s, IPPROTO_IP, + IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on)) == -1) + err(1, "setsockopt IP_BIND_ADDRESS_NO_PORT"); +#endif +#ifdef SO_REUSEPORT + if (Jflag) { + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + &on, sizeof(on)) == -1) + err(1, "setsockopt SO_REUSEADDR"); + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, + &on, sizeof(on)) == -1) + err(1, "setsockopt SO_REUSEPORT"); + } +#endif if (bind(s, (struct sockaddr *)ares->ai_addr, ares->ai_addrlen) == -1) err(1, "bind failed"); @@ -2290,6 +2321,7 @@ help(void) fprintf(stderr, "\tCommand Summary:\n\ \t-4 Use IPv4\n\ \t-6 Use IPv6\n\ + \t-B Use IP_BIND_ADDRESS_NO_PORT when binding source address\n\ \t-b Allow broadcast\n\ \t-C Send CRLF as line-ending\n\ \t-D Enable the debug socket option\n\ @@ -2298,6 +2330,7 @@ help(void) \t-h This help text\n\ \t-I length TCP receive buffer length\n\ \t-i interval Delay interval for lines sent, ports scanned\n\ + \t-J Set SO_REUSEPORT/SO_REUSEADDR on outbound source bind\n\ \t-k Keep inbound sockets open for multiple connects\n\ \t-l Listen mode, for inbound connects\n\ \t-M ttl Outgoing TTL / Hop Limit\n\ @@ -2331,7 +2364,7 @@ void usage(int ret) { fprintf(stderr, - "usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl]\n" + "usage: nc [-46BCDdFhJklNnrStUuvZz] [-I length] [-i interval] [-M ttl]\n" "\t [-m minttl] [-O length] [-P proxy_username] [-p source_port]\n" "\t [-q seconds] [-s sourceaddr] [-T keyword] [-V rtable] [-W recvlimit]\n" "\t [-w timeout] [-X proxy_protocol] [-x proxy_address[:port]]\n" -- 2.47.3

