TL;DR: don’t use Netcat, use Socat for experiments. It handles anything better.
The reason it’s not working isn’t about the named pipes (even if it’s an ugly method with other problems lurking around) but a limitation of netcat.
Once Netcat receives an UDP connection, it binds to it. So it’s not listening anymore to the port 53, it’s connected to the port that sent the initial packet, exactly as it'd do with TCP. Each time you’re doing a DNS request, the tool will change port and Netcat will never get the request. So only the first request will work.
When you set up your example, try this command before the first query:
netstat -aunp|grep -w 53
udp 0 0 0.0.0.0:53 0.0.0.0:* 12316/nc.openbsd
Do the (only working) query and try again netstat:
# netstat -aunp|grep -w 53
udp 0 0 127.0.0.1:53 127.0.0.1:44335 ESTABLISHED 12316/nc.openbsd
As you can see netcat just changed mode: From listening to looping over a connection. Because it’s UDP, Netcat won’t know automatically the “established connection” isn’t there anymore.
I have a proof of concept (that makes it work and shows the problem is related to this UDP mode) but it requires socat in addition to netcat on the client. The goal is to have all requests reach netcat using the same UDP source port. Nothing changes on the server side, but I insert socat at the start of the chain (so the last command) to force the source port of the UDP request to Netcat.
First, on the client side, do this:
ssh -N -L 6667:localhost:6667 user@server
Then, on the server side do this:
mkfifo /tmp/fifo
nc -k -l 6667 < /tmp/fifo | nc -u ip_of_dns_server 53 > /tmp/fifo
Finally, back on the client side do this:
mkfifo /tmp/fifo
nc -k -l -u 5555 < /tmp/fifo | nc 127.0.0.1 6667 > /tmp/fifo
socat udp4-listen:53,reuseaddr,fork udp:127.0.0.1:5555,sourceport=55550,reuseaddr
Now I can make multiple queries.
Before 1st query:
# netstat -aunp|egrep -w '53|5555'
udp 0 0 0.0.0.0:5555 0.0.0.0:* 12715/nc.openbsd
udp 0 0 0.0.0.0:53 0.0.0.0:* 12717/socat
After 1st:
udp 0 0 127.0.0.1:55550 127.0.0.1:5555 ESTABLISHED 12736/socat
udp 0 0 127.0.0.1:5555 127.0.0.1:55550 ESTABLISHED 12715/nc.openbsd
udp 0 0 0.0.0.0:53 0.0.0.0:* 12717/socat
After 2nd query:
udp 0 0 127.0.0.1:55550 127.0.0.1:5555 ESTABLISHED 12750/socat
udp 0 0 127.0.0.1:5555 127.0.0.1:55550 ESTABLISHED 12715/nc.openbsd
udp 0 0 0.0.0.0:53 0.0.0.0:* 12717/socat
udp 0 0 127.0.0.1:53 127.0.0.1:53255 ESTABLISHED 12750/socat
Socat would suffer the same problem but with the fork option, it listens again, and it appears it detects the previous lost “connection”; I think that causes a delay.
You can get the old behaviour (works once) if you just remove the ,sourceport=55550,reuseaddr part in the socat command.