4

I have a very simple script to run. It calls tcpreplay and then ask the user to type in something. Then the read will fail with read: read error: 0: Resource temporarily unavailable.

Here is the code

#!/bin/bash

tcpreplay -ieth4 SMTP.pcap

echo TEST
read HANDLE
echo $HANDLE

And the output is

[root@vse1 quick_test]# ./test.sh 
sending out eth4 
processing file: SMTP.pcap
Actual: 28 packets (4380 bytes) sent in 0.53 seconds.       Rated: 8264.2 bps, 0.06 Mbps, 52.83 pps
Statistics for network device: eth4
        Attempted packets:         28
        Successful packets:        28
        Failed packets:            0
        Retried packets (ENOBUFS): 0
        Retried packets (EAGAIN):  0
TEST
./test.sh: line 6: read: read error: 0: Resource temporarily unavailable

[root@vse1 quick_test]#

I am wondering if I need to close or clear up any handles or pipes after I run tcpreplay?

Jay Tang
  • 43
  • 5

3 Answers3

8

Apparently tcpreplay sets O_NONBLOCK on stdin and then doesn't remove it. I'd say it's a bug in tcpreplay. To work it around you can run tcpreplay with stdin redirected from /dev/null. Like this:

tcpreplay -i eth4 SMTP.pcap </dev/null

Addition: note that this tcpreplay behavior breaks non-interactive shells only.

Another addition: alternatively, if you really need tcpreplay to receive your input you can write a short program which resets O_NONBLOCK. Like this one (reset-nonblock.c):

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int
main()
{
    if (fcntl(STDIN_FILENO, F_SETFL,
              fcntl(STDIN_FILENO, F_GETFL) & ~O_NONBLOCK) < 0) {
        perror(NULL);
        return 1;
    }
    return 0;
}

Make it with "make reset-nonblock", then put it in your PATH and use like this:

tcpreplay -i eth4 SMTP.pcap
reset-nonblock
spbnick
  • 5,025
  • 1
  • 17
  • 22
2

While the C solution works, you can turn off nonblocking input in one line from the command-line using Python. Personally, I alias it to "setblocking" since it is fairly handy.

$ python3 -c $'import os\nos.set_blocking(0, True)'

You can also have Python print the previous state so that it may be changed only temporarily:

$ o=$(python3 -c $'import os\nprint(os.get_blocking(0))\nos.set_blocking(0, True)')
$ somecommandthatreadsstdin
$ python3 -c $'import os\nos.set_blocking(0, '$o')'
hackerb9
  • 1,545
  • 13
  • 14
1

Resource temporarily unavailable is EAGAIN (or EWOULDBLOCK) which is the error code for nonblocking file descriptor when no further data is available (would block if wasn't in nonblocking mode). The previous command (tcpreplay in this case) erroneously left STDIN in nonblocking mode. The shell will not correct it, and the following process isn't meant to work with non- default nonblocking STDIN.

In your script, you can also turn off nonblocking with:

perl -MFcntl -e 'fcntl STDIN, F_SETFL, fcntl(STDIN, F_GETFL, 0) & ~O_NONBLOCK'
niry
  • 3,238
  • 22
  • 34