5

I am trying to execute nc command from a script , my script is executing nc command on different ports of Destination using the same source port.

e.g:

nc -p 8140 -z -v -n 10.X.X.9 9090
nc -p 8140 -z -v -n 10.X.X.9 9091
nc -p 8140 -z -v -n 10.X.X.9 9092
nc -p 8140 -z -v -n 10.X.X.9 9093
and so on ...

After the 1st nc execution , for the remaining of all the lines I am getting below mentioned error message.

nc: bind failed: Address already in use
nc: bind failed: Address already in use
nc: bind failed: Address already in use

Is there any way of avoiding this situation?

saurav
  • 239

2 Answers2

10

Background

When you're attempting to use nc in this manner it's continuing to keep the TCP port open, waiting for the destination to acknowledge the receiving of the done request. This is highlighted in the TCP article on Wikipedia.

TIME-WAIT

(either server or client) represents waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request. [According to RFC 793 a connection can stay in TIME-WAIT for a maximum of four minutes known as a MSL (maximum segment lifetime).]

You can see the effects of this when I use nc similarly:

$ nc -p 8140 -v -n 192.168.1.105 80

Looking at the state of port 8140:

$ netstat -anpt | grep 8140
tcp        0      0 192.168.1.3:8140       192.168.1.105:80         TIME_WAIT   -

In fact on most Linux systems this TIME_WAIT is set to 60 seconds.

$ cat /proc/sys/net/ipv4/tcp_fin_timeout
60

If you want to see the effect yourself you can use this snippet to watch when the port becomes released.

$ date; nc -p 8140 -v -n 192.168.1.105 80 -w 1; date; \
    while netstat -anpt | grep 8140; do date; sleep 10; done; date
Tue Mar 25 09:46:59 EDT 2014
Connection to 192.168.1.105 80 port [tcp/*] succeeded!
Tue Mar 25 09:47:00 EDT 2014
tcp        0      0 192.168.1.3:8140       192.168.1.105:80        TIME_WAIT   -
Tue Mar 25 09:47:00 EDT 2014
tcp        0      0 192.168.1.3:8140       192.168.1.105:80        TIME_WAIT   -
Tue Mar 25 09:47:10 EDT 2014
tcp        0      0 192.168.1.3:8140       192.168.1.105:80        TIME_WAIT   -
Tue Mar 25 09:47:20 EDT 2014
tcp        0      0 192.168.1.3:8140       192.168.1.105:80        TIME_WAIT   -
Tue Mar 25 09:47:30 EDT 2014
tcp        0      0 192.168.1.3:8140       192.168.1.105:80        TIME_WAIT   -
Tue Mar 25 09:47:40 EDT 2014
tcp        0      0 192.168.1.3:8140       192.168.1.105:80        TIME_WAIT   -
Tue Mar 25 09:47:50 EDT 2014
Tue Mar 25 09:48:00 EDT 2014
$

Method #1 - using nc

The releasing of the port 8140 takes some time to occur. You'll either need to wait until it's been fully released (putting some sleeps in between would be 1 easy way) or by using a different port.

If you just want to see if the port @ host is open or not you could just drop the -p 8140.

$ nc -zv -n 10.X.X.9 9090-9093

Example

$ nc -zv -n 192.168.1.200 2024-50000 |& grep -v refu
Connection to 192.168.1.200 5672 port [tcp/*] succeeded!
Connection to 192.168.1.200 35766 port [tcp/*] succeeded!

NOTE: You might be tempted to try adding the -w option to nc, which instructs it to only wait a certain period of time. By default nc will wait forever. So your command would be something like this:

$ nc -p 8140 -zv -n 10.X.X.9 9090 -w 1

However in my testing on a CentOS 5.9 system using 1.84 it still continued to keep the port in use afterwards, so the best you'd be able to do is use -w 60 since that's the shortest amount of time until TIME_WAIT takes effect.

Method #2 - using nmap

If you want to use a more appropriate app for scanning a set of ports then I'd suggest using nmap instead.

$ sudo nmap -sS --source-port 8140 -p 9090-9093 10.X.X.9

Example

$ sudo nmap -sS --source-port 8140 -p 80-85 homer

Starting Nmap 6.40 ( http://nmap.org ) at 2014-03-24 21:22 EDT
Nmap scan report for homer (192.168.1.105)
Host is up (0.0059s latency).
PORT   STATE  SERVICE
80/tcp open   http
81/tcp closed hosts2-ns
82/tcp closed xfer
83/tcp closed mit-ml-dev
84/tcp closed ctf
85/tcp closed mit-ml-dev
MAC Address: 00:18:51:43:84:87 (SWsoft)

Nmap done: 1 IP address (1 host up) scanned in 11.36 seconds

Here I've setup a filter using iptraf to prove the traffic is going out to these ports using the source port of 8140.

NOTE: Pay special attention to #1 in the diagram, that shows the source port 8140, while #2 shows a couple of my destination ports that I selected, mainly 80 & 83.

               ss #1

References

slm
  • 369,824
  • Actually I have to do the outbound testing of ports on the source to the destination.In my case source port is 8140 , so i have to test that with 8140 whether it is able to connect or not. Is there any other way in which outbound of source port and inbound of the destination port can be tested ? – saurav Mar 24 '14 at 23:32
  • Use nmap instead would be my advice. nc isn't really up to what you're doing IMO. – slm Mar 25 '14 at 00:18
  • @slm nc could be up to what he wants, you've just gotta know how to tell it what to do. – mikeserv Mar 25 '14 at 04:15
  • Nice answer. You might want to explain The releasing of the port 8140 takes some time to occur with a sentence or two about TIME-WAIT. – Steven D Mar 25 '14 at 05:54
  • Thanks slm for such a wonderful explanation , actually in my case as you mentioned correctly TIME_WAIT value is 60 , so for me right now 1st solution is not feasible because i have around 100+ source and destination ports , that means (100*100) mins wait , it is definitely not going to work in my case. Is there anyway to override TIME_WAIT value ? otherwise I have to go with the nmap solution. – saurav Mar 25 '14 at 15:10
  • Yes you can change the TIME_WAIT echo 2 > /proc/sys/net/ipv4/tcp_fin_timeout, would set it to 2 seconds. Use caution w/ this method though since you're altering the timeout for the entire box. – slm Mar 25 '14 at 15:12
  • yeah correct , I have to just reset it only for the time when my script is executing later on i will reset it to the original value. - thanks – saurav Mar 25 '14 at 15:37
  • Actually I believe this is a bug in linux. While it is true that you can not reuse the same src/dst touple while the previous connection is in TIME_WAIT, by changing the destination port you have selected a different, and therefore non conflicting touple. – psusi Dec 09 '14 at 20:40
1

I guess it might as well be an answer so it is at least readable:

i=0 ; until { 
    nc -p 8140 -av -n 10.X.X.9 909${i} &&
        [ $((i=i+1)) -gt 4 ]
} 2>&- 
    do sleep 1 
done

Truth is, @slm's got a point about nmap - for handling your network and pen-testing it's an indispensable tool and it's definitely worth your while to get familiar with it. But for testing connectivity between only two machines in a 5:1 port config, it might be a little much. Then again, maybe this is a perfect opportunity to learn to use it.

Anyway, if you haven't got it at your disposal, netcat is extremely flexible. And, perhaps more importantly, nc doesn't require su root to do 0 i/o ops as does nmap.

In the above answer I just use $i to substitute the last digit of your target port with 0 for your first round and $i's incremented value thereafter. Because, as I believe, nc should return you a true so long as it can bind your local port, the variable $i will only increment if 8140 is open and nc can use it to dial out.

$i is incremented in a test to ensure you don't go beyond the 9094 port range you've specified, at which time it will finally return true thereby satisfying until and terminating the loop.

Speaking of which, until you can bind the local 8140 -port your loop will sleep 1 second (as @slm recommends) before trying again.

I just drop stderr with 2>&- so you don't have to look at couldn't bind... messages spamming your terminal. As written though, this may never be necessary, as sleep is called each time $i is incremented as well - excepting the last when the loop breaks anyway - so the 1 second pause between iterations is maybe enough to drop the bound local port and open it again for use in the next iteration.

If I've somehow mistaken the nc return value and it returns false even if it can secure 8140 locally but the target port is closed, that is easily handled with a little more specific use of $? - just let me know.

mikeserv
  • 58,310
  • Thanks mike for your answer, actually in my case i have around 100+ source and destination ports , that means (100*100) mins wait , it is definitely not going to work in my case. As I have checked the TIME_WAIT value , it is 60 secs , so it will wait for at least 60 secs before releasing the port. – saurav Mar 25 '14 at 15:15
  • Yeah, that wont work as is. Youll need to do some & backgrounding to do anything like this. – mikeserv Mar 25 '14 at 16:02
  • @tech-idiot you should bind nc to the port you want to dial out with as a proxy service with -l , then direct requests to localhost ports to be proxied out through the one proxy process. Ill update my answer a little later. – mikeserv Mar 25 '14 at 18:07