/til/

2025 0608 Bash networking redirects

I recently read instructions that surprised me. Paraphrased:

You can send messages over UDP:

echo -n "message" | nc -4u -w0 localhost 1738

Or if you use bash, you might prefer this instead:

bash -c 'echo -n "message" > /dev/udp/localhost/1738'

/dev/udp? That doesn’t look bash-specific. How did I miss that that was available as a device on Unix? Wait a second…

$ echo -n message > /dev/udp/localhost/1738
zsh: no such file or directory: /dev/udp/localhost/1738

No, this is truly a bash feature, not a generic shell one. In fact, UDP in particular seems to be completely unique to bash — zsh has a module that provides TCP networking, but no similar module for UDP networking.

It seems almost perverse. There is no /dev/udp directory (or device) at all in the filesystem, bash just intercepts any attempt to redirect to it and does networking stuff transparently. Although maybe it’s not perverse and redirection is just weirder than I thought it was. From the previously linked bash manual:

Bash handles several filenames specially when they are used in redirections, as described in the following table. If the operating system on which Bash is running provides these special files, bash will use them; otherwise it will emulate them internally with the behavior described below.

The table lists more than just networking: aside from /dev/udp/HOST/PORT and /dev/tcp/HOST/PORT, it includes /dev/fd/FD, /dev/stdin, /dev/stdout, and /dev/stderr.

This lead me to realize that these too are not POSIX! The string /dev/fd doesn’t exist at all in the online POSIX documentation, and the others are specifically called out as extensions:

The system may provide non-standard extensions. These are features not required by POSIX.1-2017 and may include, but are not limited to: … Additional character special files with special properties (for example, /dev/stdin, /dev/stdout, and /dev/stderr)

At least on my macOS desktop, the /dev/std* and /dev/fd/* devices to actually exist, so bash wouldn’t do anything special for redirection to those paths. But even the ancient bash from 2007 (!) that ships with macOS will happily talk to the special networking “device” paths.

$ /bin/bash --version
GNU bash, version 3.2.57(1)-release (arm64-apple-darwin24)
Copyright (C) 2007 Free Software Foundation, Inc.
$ /bin/bash -c 'echo -n message > /dev/udp/localhost/1738'
$ echo $?
0

Prescriptions

Being a POSIX sh purist, I can’t endorse this for lay shell scripting, but it seems really interesting as a tool for fixing very broken systems, bootstrapping very barebones systems, and penetration testing.

Other references

Responses

Webmentions

Hosted on remote sites, and collected here via Webmention.io (thanks!).

Comments

Comments are hosted on this site and powered by Remark42 (thanks!).