Netcat drops incoming packets

2019-08-02 13:49发布

问题:

I use bash commands on a Ubuntu machine for controlling a measurement instrument. Both machines are connected to the same LAN. The measurement instrument listens on TCP port 5025 for SCPI commands. The standard test - asking for the instrument's ID - works nicely:

mjh@Ubuntu:~$ echo "*IDN?" | netcat 192.168.0.10 5025
Rohde&Schwarz,ZVL-3,12345

But when I query for data (I expect 1818 ASCII characters), netcat just returns immediately:

mjh@Ubuntu:~$ echo "TRAC? TRACE1" | netcat 192.168.0.10 5025
mjh@Ubuntu:~$

However, I can query for data in a interactive telnet session without problems:

mjh@Ubuntu:~$ telnet 192.168.0.10 5025
Trying 192.168.0.10...
Connected to 192.168.0.10.
Escape character is '^]'.
TRAC? TRACE1
-6.993319702E+001,-6.755982208E+001, ... (1818 chars in total)

I want to use these commands in scripts, which is why I want to use netcat.

How can I find out why telnet works and netcat doesn't? Could it be the large package size?

So far I (unsuccessfully) tried the following:

  • using netcat -C for CRLF as line-ending
  • using netcat -t for more telnet compatibility
  • using netcat -u out of desperation

回答1:

The Root Cause

Netcat and telnet handle the connections differently.

Telnet

  • Establish TCP connection with instrument
  • When user enters data, send it to instrument (in this case "TRAC? TRACE1")
  • Receive Data from instrument (several packets, if need be)
  • When user ends the interactive session, close TCP connection with instrument
  • Exit program

Netcat

  • Establish TCP connection with instrument
  • Send data that was piped into netcat (in this case "TRAC? TRACE1")
  • Immediately ask for connection to be terminated
  • Receive whatever data the instrument squeezes through
  • Exit program after instrument acknowledges and finishes the closing of the TCP connection.

Specifically, when using netcat for querying the ID, the instrument returns the ID immediately within its ACK. But when asking for data, the instrument takes a bit longer to fetch it, and the network adapter in the instrument closes the connection before the data can be sent.

Finding the root cause

A comment suggested to use these tools, but it's not trivial, so I'll delve into the general procedure:

  • On the Ubuntu machine, install tcpdump

    sudo apt-get install tcpdump
    
  • Find the id of your network adapter (Look for eth0, eth1, or anything that reminds you of your network adapter. In my case I got eth1.)

    sudo tcpdump -D
    
  • Capture all traffic that either goes to or comes from port 5025 (the SCPI port). The s0 option tells tcpdump to capture the whole package, not just the first few bytes. The -w option makes tcpdump save the raw data to a file.

    sudo tcpdump -i eth1 -s0 port 5025 -w netcat_trac.dump
    
  • Open a second terminal window and execute a netcat command (or telnet session):

     echo "TRAC? TRACE1" | netcat 192.168.0.10 5025
    
  • In the first terminal window, stop tcpdump by pressing CTRL+C

  • Repeat this for several different scenarious, saving the output to different .dump files each time.

  • On any PC with a GUI (Windows, in my case, but also works on Ubuntu), install Wireshark and look at the .dump files.

  • Pay attention to the series of SYN ("I want to make a connection"), SYN+ACK ("I understand you and also want to make a connection with you"), FIN+ACK(I want to stop talking to you) flags in the capture packets. Compare the order in which these flags appear for the different scenarios. If you have no idea what this mean, this is a great introduction. (If you want to get into gnarly details, also pay attention to the "seq" and "ack" numbers.)

A Solution

Tell netcat to wait before closing the connection by using the -q switch.

echo "TRAC? TRACE1" | netcat -q 1 192.168.0.10 5025

In the command above, the wait time is 1 second.

I am sure there are better solution (wait for a packet with PSH set instead of a fixed time that may either be too short or too long), but this works well enough for me.