F35 is an end-to-end DNS resolver scanner for real tunnel testing.
It does not only ask a DNS question and call that a success. It actually:
- starts a tunnel client
- uses one resolver from your list
- waits for the tunnel to become usable
- sends a real HTTP request through the tunnel
- prints only resolvers that really pass traffic
This is useful when you want to find resolvers that still have outside connectivity during heavy filtering or shutdown conditions.
A resolver is the DNS server IP you want to test.
Examples:
1.1.1.1
8.8.8.8:53
10.10.34.1If you give only an IP, F35 uses port 53 automatically.
You need all of these:
- a file with resolver IPs
- a working tunnel domain
- one tunnel client:
dnstt-clientslipstream-clientvaydns-client
- the extra flags that your tunnel client needs, passed with
-a
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o f35 .-rfile that contains resolver IPs-ewhich tunnel client to use:dnstt,slipstream, orvaydns-dtunnel domain-aextra flags for your tunnel client, for example pubkey, timeouts, log level, or custom tuning-xproxy protocol F35 uses for the request through the tunnel this must match what your tunnel path or server-side target expects wrong-xcan make healthy resolvers look dead default issocks5h-Uproxy username if the tunnel exit requires authentication-Pproxy password if the tunnel exit requires authentication-Prequires-U-utest URL used for the probe request through the tunnel default ishttp://www.google.com/gen_204-whow many resolvers to test at the same time-show long to wait before the HTTP test, in milliseconds this is important because the tunnel may need time to become usable-tprobe request timeout in seconds-proberun a quick connectivity probe through the tunnel-downloadrun a real download test through the tunnel enabled by default-download-urlHTTP URL used for the download test default ishttps://speed.cloudflare.com/__down?bytes=100000-download-timeouttimeout in seconds for the download test default is5-Rnumber of retries for each resolver after the first failed attempt-lstarting local port for local tunnel listeners useful if you want to avoid port collisions or run multiple scans-pfull path to the tunnel client binary if it is not inPATH-whoisrun a whois lookup for resolver organization and country-whois-timeouttimeout in seconds for the whois lookup default is15-jsonprint one JSON object per result line instead of plain text-qsuppress startup and completion logs
Use these as the main knobs:
-swait longer here if the tunnel starts too slowly-traise this if the quick probe is timing out-download-timeoutraise this if the download test starts but does not finish in time-whois-timeoutraise this if the whois lookup is too slow
Good starting values:
- slow tunnel startup: increase
-s - weak or filtered path: increase
-download-timeout - slow whois API: increase
-whois-timeout - only probe fails: increase
-t
-a is only for tunnel client flags.
Examples:
- DNSTT:
-a '-pubkey YOUR_PUBLIC_KEY' - VayDNS:
-a '-pubkey YOUR_PUBLIC_KEY -log-level info -udp-timeout 200ms'
F35 automatically fills these parts for you:
- resolver address
- local listen address
- domain
For dnstt, F35 places -a before the positional domain and listen arguments.
If you are new, start with something like this:
f35 -r resolvers.txt -e dnstt -d t.example.com -x socks5h -a '-pubkey YOUR_PUBLIC_KEY'What this means:
- read resolvers from
resolvers.txt - use
dnstt-client - connect to
t.example.com - send the HTTP test through the tunnel using the
socks5hprotocol - pass the public key to the client
f35 -r resolvers.txt \
-e dnstt \
-d t.example.com \
-x socks5h \
-a '-pubkey YOUR_PUBLIC_KEY'f35 -r resolvers.txt \
-e vaydns \
-d t.example.com \
-x socks5h \
-a '-pubkey YOUR_PUBLIC_KEY -log-level info -udp-timeout 200ms -open-stream-timeout 7s -idle-timeout 10s -keepalive 2s -udp-workers 200 -rps 300 -max-streams 0 -max-qname-len 101 -max-num-labels 2'f35 -r resolvers.txt \
-e slipstream \
-d t.example.com \
-x socks5hUse this if the proxy exposed by your tunnel requires a username and password:
f35 -r resolvers.txt \
-e dnstt \
-d t.example.com \
-x socks5h \
-U myuser \
-P mypass \
-a '-pubkey YOUR_PUBLIC_KEY'-P only works together with -U.
f35 -r resolvers.txt -e dnstt -d t.example.com -x socks5h -a '-pubkey YOUR_PUBLIC_KEY' | tee healthy.txtf35 -r resolvers.txt -e vaydns -d t.example.com -x socks5h -p ./vaydns-client -a '-pubkey YOUR_PUBLIC_KEY'This is useful when resolvers are slow but still usable.
f35 -r resolvers.txt -e vaydns -d t.example.com -x socks5h -w 50 -s 2000 -t 8 -R 2 -a '-pubkey YOUR_PUBLIC_KEY'Meaning:
- fewer concurrent workers
- longer tunnel warm-up wait
- longer HTTP timeout
- retry failed resolvers
f35 -r resolvers.txt -e vaydns -d t.example.com -x socks5h -whois -a '-pubkey YOUR_PUBLIC_KEY'This keeps the enabled checks independent, and if the whois lookup succeeds, it also prints org and country for that resolver IP.
This is most useful when the resolver IP itself belongs to the network you care about. If your tunnel goes into a more advanced upstream chain, this extra lookup can be less meaningful.
f35 -r resolvers.txt -e vaydns -d t.example.com -x socks5h -whois -json -a '-pubkey YOUR_PUBLIC_KEY'Use this if you want to parse the output in another program.
F35 does not generate advanced proxy protocol packets by itself.
It only sends a normal HTTP request through the tunnel using the protocol selected with -x.
Examples:
- if your tunnel path expects SOCKS, use
-x socks5or-x socks5h - if your tunnel path expects HTTP proxy traffic, use
-x http
If you use something more advanced behind the tunnel, like vless+ws, F35 is not generating native vless+ws traffic.
It is only checking whether the tunnel path can move a request and return any response.
That means:
- the download request is the strongest signal
- whois and probe are weaker checks
- F35 does not require HTTP
200 - even
400or404can still prove that the tunnel is working -whoismay be less useful in those advanced chains- wrong
-xcan ruin scan results
By default, scan status is printed to stderr with a short scan started and scan finished line.
Use -q to silence those logs and keep only result lines on stdout.
1.2.3.4:53 342ms download="ok" whois="ok" probe="fail"
5.6.7.8:53 89ms download="ok" whois="fail" probe="ok"Only usable resolvers are printed.
A resolver is considered usable if at least one enabled check succeeds. By default, download is the primary signal.
F35 does not require HTTP 200.
Even a 400 or 404 can still prove that the tunnel is working.
Latency is colored on terminal output:
- green:
0-2000ms - yellow:
2000-6000ms - red:
6000ms+
If you pipe the output to a file or another command, colors are not printed.
1.2.3.4:53 342ms download="ok" whois="ok" probe="fail" org="Information Technology Company PJSC" country="Iran"
5.6.7.8:53 2140ms download="ok" whois="fail" probe="ok"The output stays simple and the status fields always appear in the same order.
{"resolver":"1.2.3.4:53","latency_ms":342,"probe":"fail","whois":"ok","download":"ok","org":"Information Technology Company PJSC","country":"Iran"}
{"resolver":"5.6.7.8:53","latency_ms":2140,"probe":"ok","whois":"fail","download":"ok"}If you do not know what to tune first, try this order:
- keep
-x socks5h - if output is empty, increase
-s - if working resolvers are slow, increase
-t - if results are unstable, lower
-w - if some resolvers fail randomly, add
-R 1or-R 2
The selected tunnel client binary was not found.
Fix it with one of these:
- install the client
- add it to
PATH - use
-p /full/path/to/client
Usually one of these is wrong:
- domain
- engine
- pubkey or other tunnel client flags inside
-a - wait time is too short
- timeout is too short
Try this:
-s 2000 -t 8 -R 1If you set a proxy password, you must also set a proxy username.
Try:
- lower
-w - increase
-s - increase
-t - add retries with
-R
Put the same client flags you normally use when running your tunnel client manually.
F35 is not replacing your tunnel client config. It is only fuzzing resolvers and local listen ports around that client command.