How to send only one UDP packet with netcat?
Asked Answered
C

6

161

I want to send only one short value in a UDP packet, but running the command

echo -n "hello" | nc -4u localhost 8000

I can see that the server is getting the hello stuff but I have to press Ctrl+c to quit the netcat command.

How can I make it quit after sending hello?


Sorry, for the noise, I re-read the man page and found the -q option.

 echo -n "hello" | nc -4u -q1 localhost 8000

works (it quits after 1 second).

For some reason it does not work with -q0.

Clothes answered 14/3, 2012 at 4:52 Comment(1)
Man page on debian: -q seconds: after EOF on stdin, wait the specified number of seconds and then quit. If seconds is negative, wait forever.Pooley
S
257

If you are using bash, you might as well write

echo -n "hello" >/dev/udp/localhost/8000

and avoid all the idiosyncrasies and incompatibilities of netcat.

This also works sending to other hosts, ex:

echo -n "hello" >/dev/udp/remotehost/8000

These are not "real" devices on the file system, but bash "special" aliases. There is additional information in the Bash Manual.

Seymour answered 15/5, 2013 at 15:12 Comment(16)
Ok, you are right, let me just make it explicit that this won't work with ZSH.Longwinded
How does one get this packet?Remittent
This is way better than mucking with netcat. Thanks for the tip!Mesopotamia
So much fast.simpler/more reliable/better than netcat for a udp packet. Thanks!Saturday
+1 for answer, @JúlioTurollaRibeiro, no need to be explicit in comment, answer is explicit enough : "If you are using bash ..."Laundrywoman
For some reason, I needed to use 127.0.0.1 instead on localhost on Ubuntu 14.04. (Yes, I do have localhost in /etc/hosts.)Neckband
@Neckband Good tip. This also applies for OS X 10.11. While also running bash, as zsh doesn't have the /dev/udpRalphralston
On OS X 10.10 there's no /dev/udp but simple echo "message" > /dev/udp/127.0.0.1/5000 (for example) works like a charmErgosterol
/dev/udp/ is not a real file. It's only a file name interpreted specially by bash.Seymour
maybe a mention that echo -n is writing without a newline charBlowbyblow
@PeterEisentraut So that's why it doesn't show up with ls -la /dev/udp ...?Unsphere
@Unsphere Yes, because it only exists in bash, not in ls.Seymour
So what if we actually have something at /dev/udp. How do we access that? @PeterEisentrautUnsphere
localhost doesn't work but 127.0.0.1 and 0.0.0.0 works. Great hint, thx!Cormorant
I tried this to talk to another machine on my LAN like echo -n "hello" >/dev/udp/10.1.1.10/4000 and it doesn't workFunnyman
This is pure gold! I am going to use it for the rest of my life. Thank you so much for sharing.Organize
C
51

I did not find the -q1 option on my netcat. Instead I used the -w1 option. Below is the bash script I did to send an udp packet to any host and port:

#!/bin/bash

def_host=localhost
def_port=43211

HOST=${2:-$def_host}
PORT=${3:-$def_port}

echo -n "$1" | nc -4u -w1 $HOST $PORT
Collapse answered 4/12, 2012 at 19:19 Comment(1)
OS X works this: "echo -n "test" | nc -4u -w0 localhost 9999" as SimonW saysPopsicle
O
17

On a current netcat (v0.7.1) you have a -c switch:

-c, --close                close connection on EOF from stdin

Hence,

echo "hi" | nc -cu localhost 8000

should do the trick.

Otto answered 21/7, 2017 at 14:15 Comment(2)
Important to note that this is true only for GNU netcat, but not for BSD netcat.Kirbee
For clarity, with Linux-based netcat, the -c option requires a command as an argument, which "executes the given argument via /bin/bash" - commandlinux.com/man-page/man1/nc.1.htmlRosin
F
12

I had the same problem but I use -w 0 option to send only one packet and quit. You should use this command :

echo -n "hello" | nc -4u -w0 localhost 8000
Fairweather answered 9/7, 2018 at 5:59 Comment(2)
nc 1.10-41+b1 does not accept -w0. Error: invalid wait-time 0Transceiver
@Transceiver that looks like a nc.traditional version string. -q0 should work for you.Prorogue
S
6

Netcat sends one packet per newline. So you're fine. If you do anything more complex then you might need something else.

I was fooling around with Wireshark when I realized this. Don't know if it helps.

Sanctuary answered 25/5, 2013 at 2:10 Comment(4)
I think this is only correct for TCP. With UDP, it will send multiple lines in one packet (if they fit).Changeover
No. Simply test echo -n "hello\nworld" >/dev/udp/localhost/514 and you'll get 2 linesAthens
@bebbo, 2 lines, one packetTellurite
@Athens is right. This answer wasn't even correct for UDP specifically as it does this in TCPSanctuary
P
3

Unfortunately nc is not a unique name for a single tool. To find out which nc you have, look at the first line of output from nc -h. To send a single UDP packet and exit immediately, use the appropriate arguments for your specific nc.

  • GNU nc -uc localhost 8000 <<<hello
  • BSD nc -uq0 localhost 8000 <<<hello
  • traditional nc -uq0 localhost 8000 <<<hello
  • BusyBox nc does not support UDP
  • Others? Please leave a comment!

Related but thankfully not calling themselves nc:

  • nmap: ncat -u --send-only localhost 8000 <<<hello
  • bash: echo hello >/dev/udp/localhost/8000
  • socat - UDP:localhost:8000 <<<hello
  • sendip -p ipv4 -p udp -ud 8000 -d $'hello\n' localhost
  • packetsender -ua localhost 8000 $'hello\n'
  • There are so many more! But the original question was about netcat...

If you want a portable nc wrapper for sending a single UDP packet, try this as nc-udp-oneshot.sh:

#!/bin/sh

helpword=$(nc -h 2>&1 | awk '{print$1;exit}')

case $helpword in
  *GNU*) args=-uc ;;
  *) args=-uq0 ;;
esac
exec nc $args "$@"

Now you can run echo -n hello | ./nc-udp-oneshot.sh with whichever nc happens to be installed. Or xxd -r -p <<<68656c6c6f | ./nc-udp-oneshot.sh for sending more complicated binary data, represented in hex.

Prorogue answered 13/2, 2023 at 1:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.