27

CentOS 5.9

For testing purposes, I want my CentOS server to listen on a secondary virtual IP (eth0:0). I'm familiar with nc -l -p <port> but it only listens on the primary. Is there a way I can specify a specific IP for the listener to use?

If not, is there another "stock" utility in CentOS 5.9 that can do this?

3 Answers 3

48

The syntax depends on the netcat package.

netcat-openbsd:

# General form
nc -l ip port 
# Example
nc -l 192.168.2.1 3000

netcat-traditional:

# General form
nc -l -p port -s ip
# Example
nc -l -p 3000 -s 192.168.2.1

A simple way (at least in bash) for telling them apart in scripts is:

if ldd $(type -P nc) | grep -q libbsd; then
    nc -l 192.168.2.1 3000
else
    nc -l -p 3000 -s 192.168.2.1
fi

You can also run this one-liner to check manually:

if ldd $(type -P nc) | grep -q libbsd; then echo "netcat-openbsd"; else echo "netcat-traditional"; fi

Example output will be netcat-traditional or netcat-openbsd.

8
  • This is exactly what the man page says. May 31, 2013 at 16:36
  • @MichaelHampton I am not sure whether I understand correctly what you mean. May 31, 2013 at 16:39
  • 1
    I think in netcat-traditional you can do -l -p
    – user
    May 31, 2013 at 16:39
  • 1
    @MichaelHampton I guess I will take quite a while yet until I understand the practice rules of upvoting. If I have a look at what I get upvotes for (and much worse: What not for!) then I could cry. But it looks like this big problem's solution kicks me above the desired 3,000 points... (I noticed that on Unix & Linux my interest in rep dropped a lot after that) May 31, 2013 at 16:43
  • 1
    @SAMPro The answer was not incorrect but incomplete. May 13, 2020 at 20:11
10

To be complete, this command should work too:

nc -l -p port -s ip

# Example
nc -l -p 3000 -s 192.168.2.1

It works with nc6 version 1.0 and netcat (The GNU Netcat) 0.7.1.

The command from @Hauke Laging doesn't work with nc6 (used in Debian).

5
  • 2
    The only way I can get to specify the listening interface on Ubuntu's nc.
    – Jules
    Aug 5, 2016 at 15:33
  • 2
    nc says that you cannot use both -s and -l together
    – SunSparc
    Oct 11, 2016 at 22:42
  • 1
    @SunSparc yet it is the only way to go for me to specify both local ip and local port in server mode - no other combination of options works here (nc v1.10-38, debian) Mar 22, 2017 at 18:01
  • I think the issue could be that different netcat versions behave differently. I can't seem to get a version string out of mine, but there are at least two packages netcat-traditional vs netcat-openbsd. netcat -vvlp 4445 -s 172.17.0.1 gives me listening on [172.17.0.1] 4445 ... vs netcat -vvl 172.17.0.1 4445 gives me listening on [any] 36539 ...
    – relet
    Oct 3, 2017 at 8:30
  • I had to specify the -s flag on debian buster.
    – Karl Pokus
    Feb 7, 2020 at 7:33
1

General netcat (nc) usage instructions, including setting the IP address to bind to when receiving, or to send to when sending

This one-liner (modified from @Hauke Laging's answer), shows that I have the netcat-openbsd type on Ubuntu 22.04:

if ldd $(type -P nc) | grep -q libbsd; then echo "netcat-openbsd"; else echo "netcat-traditional"; fi

My output is:

netcat-openbsd

The other type, per Hauke's wording, would be netcat-traditional.

Looking at the very bottom of man nc, I can also see that I have the BSD type:

BSD March 31, 2021 BSD

With this version of netcat (also callable as nc), here are the various ways to specify the IP address when both listening and sending.

Note that in all examples, you might instead call the "IP" or "IP Address" simply the "host", regardless of whether it is sending or receiving. In this way, each connected process is a "host".

General netcat listening commands using netcat-openbsd

To listen, use -l in all of the commands. Note that he -s argument specifies the source IP address, and this command style works when listening only.

# -------
# TCP
# - withOUT `-u`
# -------

# General form 1 (netcat-openbsd only)
# - see Hauke's answer: https://serverfault.com/a/512337/357116
nc -l <ip> <port>
# example
nc -l 127.0.0.1 30000

# General form 2 (netcat-traditional-style)
# - see @schlicht's answer: https://serverfault.com/a/765633/357116
nc -l -s <ip> -p <port>
# example
nc -l -s 127.0.0.1 -p 30000

# -------
# UDP
# - just add `-u` to all commands above
# -------

# General form 1 (netcat-openbsd only)
# - see Hauke's answer: https://serverfault.com/a/512337/357116
nc -lu <ip> <port>
# example
nc -lu 127.0.0.1 30000

# General form 2 (netcat-traditional-style)
# - see @schlicht's answer: https://serverfault.com/a/765633/357116
nc -lu -s <ip> -p <port>
# example
nc -lu -s 127.0.0.1 -p 30000

To bind to and listen to INADDR_ANY, which means "any interface host IP address", you can use IP address 0, like this:

nc -l 0 30000
# OR
nc -l -s 0 -p 30000

Or, even better, just omit the IP address entirely to bind to and listen on INADDR_ANY, like this:

nc -l 30000
# OR
nc -l -p 30000

General netcat sending commands using netcat-openbsd

To send, just remove the -l from all commands. Note that the -s argument specifies the source IP address, and this command style works when listening only.

# -------
# TCP
# - withOUT `-u`
# -------

# General form (netcat-openbsd only)
# - see Hauke's answer: https://serverfault.com/a/512337/357116
nc <ip> <port>
# example
nc 127.0.0.1 30000

# -------
# UDP
# - just add `-u` to all commands above
# -------

# General form (netcat-openbsd only)
# - see Hauke's answer: https://serverfault.com/a/512337/357116
nc -u <ip> <port>
# example
nc -u 127.0.0.1 30000

To send a particular binary file, use < filename.bin at the end.

Example: send filename.bin as a UDP packet on IP address 127.0.0.1 (the inter-process-communication (IPC) loopback interface) port 30000:

nc -u 127.0.0.1 30000 < filename.bin

Note that filename.bin in this example contains a binary, packed C struct data message with some variables in it, just as if you were writing a C program to send a struct as a UDP packet. See how it is generated in C, in the bottom of my answer here.

To send to INADDR_ANY, which means "any IP address on any interface", you can use IP address 0, like this:

nc 0 30000

Interactive examples

Basic TCP/IP single listener (server), single sender (client)

  1. In one terminal, start a TCP/IP listener (-l) ("server") on your local loopback interface (IP 127.0.0.1), port 30000:

    nc -l 127.0.0.1 30000
    
  2. In another terminal, start an interactive TCP/IP sender ("client") to send to the same IP and port:

    nc 127.0.0.1 30000
    

    Now, type hey, and press Enter. You'll see it echoed in the sender's terminal, and received and printed in the listener's terminal. You can type more messages, pressing Enter after each one to send it. It's like a one-way chat program.

UDP single listener (server), multiple senders (clients)

  1. In one terminal, start a UDP (-u) listener (-l) ("server") on your local loopback interface (IP 127.0.0.1), port 30000. Pass -k to enable it to receive from multiple senders by listening again after each receive:
    nc -luk 127.0.0.1 30000
    
  2. In a second terminal, start an interactive UDP (-u) sender ("client"):
    nc -u 127.0.0.1 30000
    
  3. In a third terminal, start another interactive UDP (-u) sender ("client"):
    nc -u 127.0.0.1 30000
    
  4. You can now type repeatedly into either of the sender terminals above, and the listener will print out what it receives from either of the senders.

Proof that IP address 0, or 0.0.0.0, is INADDR_ANY, and binds to all interfaces (all interface host IP addresss):

Run ifconfig to see all of your interfaces and their corresponding IP addresses. I have two interfaces:

  1. lo, which is my virtual local "loopback" interface, with IP address 127.0.0.1, and
  2. wlp0s20f3, which is my wireless card, with IP address 192.168.0.67.

We will use those in the commands below:

Basic TCP/IP single listener (server) bound to INADDR_ANY (all interfaces), with sender (client) sending to IP (host) 127.0.0.1 OR 192.168.0.67

In this example, we'll listen and bind to INADDR_ANY, and see that a sender sending to either of my valid interface host IP addresses (127.0.0.1 or 192.168.0.67, as shown by ifconfig) can successfully connect to and send to this listener.

  1. In one terminal, start a TCP/IP listener (-l) on INADDR_ANY (IP address 0) and port 30000:

    nc -l 0 30000
    
  2. In a second terminal, start an interactive TCP/IP sender ("client") to your local loopback IP address of 127.0.0.1, and port 30000:

    nc 127.0.0.1 30000
    

    Now type hello, and press Enter. It works! The listener receives the data even when the sender sends to IP address 127.0.0.1. This is because the listener is bound to INADDR_ANY, meaning it is listening on all interfaces, on each respective IP address for that interface, as shown by ifconfig.

  3. Now kill both processes with Ctrl + C (note: if you kill just the sender, it kills both processes at once), and restart the listener in terminal 1:

    nc -l 0 30000
    
  4. In the second terminal, start the sender again, but this time sending data to your external wireless interface at its host IP address of 192.168.0.67, as previously shown by ifconfig above:

    nc 192.168.0.67 30000
    

    Type a word and press Enter, and again, the receiver will receive it, since it is listening on all of your active interfaces, as shown by ifconfig, since it is bound to host IP address 0, which is the same as 0.0.0.0, which represents INADDR_ANY, by common convention.

It is important to note here that even though we are binding our listener above to INADDR_ANY (all interfaces), this does not mean it can have multiple connections at once! It is still unicast, meaning: a 1-to-1 relationship. It's just that it is bound to and listening on all interfaces, so a client can connect to this server listener on any of my two interface host IP addresses as shown by ifconfig, rather than just via one single interface host IP address that I would otherwise have to specify, choosing between any available interface host IP addresses shown by ifconfig.

Basic TCP/IP single listener (server) bound to interface host IP address 127.0.0.1, with sender (client) sending to INADDR_ANY (all interfaces)

In this example, we'll do the reverse of the previous example. We will bind to and listen on a specific interface host IP address, and show that a sender connecting to and sending to INADDR_ANY (all interfaces) can still reach this listener.

  1. In one terminal, start a TCP/IP listener (-l) on interface host IP address 127.0.0.1 port 30000:

    nc -l 127.0.0.1 30000
    
  2. In a second terminal, start an interactive TCP/IP sender ("client") to INADDR_ANY (all interfaces, as represented by interface host IP address 0, or 0.0.0.0), and port 30000:

    nc 0 30000
    # Or
    nc 0.0.0.0 30000
    

    Now type hello, and press Enter. It works! The listener receives the data even when the sender sends to INADDR_ANY (all interfaces) instead of to interface host IP address 127.0.0.1.

Note that if I listen on interface host IP address 192.168.0.62, which is my other interface's host IP address, as shown by ifconfig, for some reason the above does not work. I don't know why. Maybe it's a bug in netcat.

Again, it is important to recognize here that even though we are sending to INADDR_ANY (all interface host IP addresses), this does not mean we can have multiple connections at once! It is still unicast, meaning: a 1-to-1 relationship. The TCP/IP sender will connect to the first TCP/IP listener it can, and just send to that one connection point, keeping that connection alive. UDP will do the same, acting as unicast and sending to a single UDP listener at a time, except that unlike TCP/IP, it does not connect, nor does it keep any connection alive. It just fires and forgets the data, and moves on.

I don't know how the resolving is done as to which receiver will get the data if multiple receivers are listening on the same interface host IP address and port at the same time.

See also

  1. For more on this, and to see how to generate a binary filename.bin packet from a packed struct in C, see my Q&A here: "Connection refused" when I try to send a UDP packet with netcat on an embedded-linux board.
  2. See also my git & Linux cmds, help, tips & tricks - Gabriel.txt notes document in my eRCaGuy_dotfiles repo. Search it for netcat, nc, and socat.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .