I can do the following to send binary data in netcat:
echo -e '\x80' | nc host portBut I don't want to do it like this, what I want is to connect to a server:
nc 192.168.1.115 12345And then send some text:
aaaaaaaaaabbbbbbbbbbcccccccccccAnd then send some binary data:
0x80 0xF4 0x12How can I do that?
24 Answers
Note: while following this solution, type commands in a single shell session (or use a single script) unless said otherwise. This is because it uses variables and file descriptors, they are not directly available outside their original session.
Create a temporary fifo. The right way to create a temporary file is with mktemp. Unfortunately it cannot create fifos. It can create a temporary directory though:
tmpd=`mktemp -d`
tmpf="$tmpd"/fifo
mkfifo "$tmpf"
printf "%s\n" "$tmpf" # just to know the path to the fifo, it may be useful laterAlternatively you can create a named fifo by hand in some fixed or ad-hoc location. It's up to you.
Create a background process that will read the fifo and pass data to a server:
nc 192.168.1.115 12345 < "$tmpf" &
ncpid=$! # PID may be useful laterPay attention if nc doesn't exit prematurely. Assuming there's no problem with the connection itself nor the server, the above background command will stay connected until you finish sending the first bunch of data through the fifo. But you want it to stay open and accept multiple writes, so open the fifo and don't close it (yet):
exec 3> "$tmpf"Now you can send whatever you like through the fifo and the background connection persists:
echo abcd >&3 # sends text
echo -e '\x80' >&3 # sends "binary"
cat /etc/issue >&3 # sends file
cat >&3 # type whatever you want, terminate with Ctrl+DAny of this commands can be invoked with the path to the fifo instead of &3, if only you know the path. Knowing the path, you can write to the fifo from the same or another shell session:
cat > /path/to/the/fifo # type whatever you want, terminate with Ctrl+DOr you can open a descriptor in another session in a similar manner like in the original one. Whatever way you write to the fifo, the nc will pass it to the remote server in a single connection.
But beware of race conditions. Using a single descriptor inside a single shell session is a good way to avoid them.
After you pass whatever data you need, terminate the nc and close the descriptor in the original shell session:
kill $ncpid
exec 3>&-Note in some circumstances the sole latter command is enough to make the background nc exit; it depends on what you did and what you are still doing with the fifo. For this reason I chose to kill the nc explicitly.
Remove the temporary directory and its content (i.e. the fifo):
rm -r "$tmpd"Final note:
It's not necessary to put nc into background in the first place. You can run it in one terminal, write to the fifo (knowing its path) from another one. This way you can easily monitor its state. Tailor this solution to your needs.
The following seems to work:
while read -r; do echo -en "$REPLY" | nc ...; doneThis allows you to include \xNN escape sequences with your normal data, as in:
aaaaaaaaaabbbbbbbbbbccccccccccc\x80\xF4\x12Remember to double any literal \ characters in your text input. Note that the use of read -r and $REPLY instead of a variable stops the stripping of leading and trailing blanks.
This doesn't add a new-line to the end of the buffer, so you need either to omit the n option from the echo command or to type \x0a where you want a new-line.
I can't set up nc at present, but I have tested with:
while read -r; do echo -en "$REPLY" | cat | xxd; doneFor testing, you can use od -ct x1 if you don't have xxd; or use od -c if you are happy to see binary characters in octal. You can omit cat | from the pipe: I included it as possibly a better simulation of the use of nc.
You can get help from a named pipe to do it, with a little trick:
remote$ nc -v -n -l -p 8888 > /tmp/data
Listening on [0.0.0.0] (family 0, port 8888)
Connection from 10.0.3.1 47108 received!
local:1$ mkfifo /tmp/fifo
local:1$ nc -v -n <>/tmp/fifo 10.0.3.66 8888
Connection to 10.0.3.66 8888 port [tcp/*] succeeded!It's important to open the fifo read-write (or else have an other neutral process like sleep 9999 >/tmp/fifo keeping it opened for writing) else the first (end of) write done will end netcat's read loop. Hence the <>.
local:2$ echo aaaaaaaaaabbbbbbbbbbccccccccccc > /tmp/fifo
local:2$ cat /bin/ls > /tmp/fifo # sends the binary contents of the file /bin/ls, which would probably garble the input or output
local:2$ cat > /tmp/fifo
Some more interactive text
(local:1$ )
^C
remote$ od -c /tmp/data|head -4
0000000 a a a a a a a a a a b b b b b b
0000020 b b b b c c c c c c c c c c c \n
0000040 177 E L F 002 001 001 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000060 003 \0 > \0 001 \0 \0 \0 0 T \0 \0 \0 \0 \0 \0 3 If you know the two pieces of data ahead of time, then try this:
$ ( echo "aaabbbccc"; echo -en "\x80\xf4\x12" ) | hexdump -Cv
00000000 61 61 61 62 62 62 63 63 63 0a 80 f4 12 |aaabbbccc....|
0000000dIf you want to be able to have more control (use the keyboard, etc...), then try this:
$ ( cat; cat | xxd -r -p ) | hexdump -Cv
aaabbbccc
80f412
00000000 61 61 61 62 62 62 63 63 63 0a 80 f4 12 |aaabbbccc....|
0000000dNote: you need to press Ctrl + D to end each cat... so here I typed (including the Returns - EOT must appear at the beginning of the line):
aaabbbccc
^D
80f412
^D