cloudflare / cloudflared

Cloudflare Tunnel client (formerly Argo Tunnel)
https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-guide
Apache License 2.0
8.86k stars 777 forks source link

🐛 Failed to request quick Tunnel may caused by program internal nameserver(detection?) #793

Open zhangjing-GitHub-Code opened 1 year ago

zhangjing-GitHub-Code commented 1 year ago

Describe the bug (maybe i should ask this in termux...) I use cloudflared on Termux, Android 12 when i run ./cloudflare tunnel --url ..., it logs

❯ ./cloudflared tunnel --url ssh://localhost:8022 --proxy-dns-address 0.0.0.0
2022-10-27T12:26:36Z INF Thank you for trying Cloudflare Tunnel. Doing so, without a Cloudflare account, is a quick way to experiment and try it out. However, be aware that these account-less Tunnels have no uptime guarantee. If you intend to use Tunnels in production you should use a pre-created named tunnel by following: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps

2022-10-27T12:26:36Z INF Requesting new quick Tunnel on trycloudflare.com... 
failed to request quick Tunnel: Post "https://api.trycloudflare.com/tunnel": dial tcp: lookup api.trycloudflare.com on [::1]:53: read udp [::1]:58253->[::1]:53: read: connection refused

It seems like the cloudflared thinks nameserver is ::1, but $PREFIX/etc/resolv.conf contains:

nameserver 9.9.9.9
nameserver 114.114.114.114
nameserver 8.8.8.8
nameserver 8.8.4.4

And nslookup can get correct ip address of api.trycloudflare.com.

❯ nslookup api.trycloudflare.com                
Server:         9.9.9.9                         
Address:        9.9.9.9#53                                                                      
Non-authoritative answer:                       
Name:   api.trycloudflare.com                   
Address: 104.17.124.55                          
Name:   api.trycloudflare.com                   
Address: 104.17.123.55

To Reproduce Steps to reproduce the behavior:

  1. Run './cloudflared tunnel' (in termux v0.118.0)
  2. See error

If it's an issue with Cloudflare Tunnel: but not with account(I logined my account but I use tunnel without account) ~3. Tunnel ID :~ ~4. cloudflared config:~

Expected behavior The program can get api.trycloudflare.com's ip address then create my tunnel.

Environment and versions

Logs and errors up there.

Additional context none

zhangjing-GitHub-Code commented 1 year ago

??

niranjanshr13 commented 1 year ago

@zhangjing-GitHub-Code the way you access termux ssh through cloudflare tunnel is.

  1. have a sshd running.
  2. give a user password passwd
  3. check if it is working ssh localhost -p 8022 ; default ssh port in termux is 8022.
  4. install cloudflared in termux pkg install cloudflared
  5. cloudflared login a url will be given, you login a cloudflare in your phone and go to that page again. click the domain you want to use.
  6. cloudflared tunnel create temp-tunnel-name
  7. in termux go to ls ~/.cloudflared/ => you should see cert.pem and uuid.json
  8. copy that uuid string without json.
  9. create a new file on ~/.cloudflared/config.yaml
    tunnel: uuid
    credentials-file: absolute path of that uuid.json (try pwd while on ~/.cloudflared/ to find a pathname)
  10. run cloudflared tunnel run
  11. exit from that command
  12. you will see a new tunnel in cloudflared zero trust.
Liquorice10113 commented 1 year ago

I encountered the same problem and, after some research, I found a solution. Essentially, many Linux distributions include a local resolver that listens on [::1]:53. This resolver is responsible for forwarding DNS queries to the actual DNS server and caching the responses. Cloudflared attempts to query its edge server's IP address by sending a DNS query to the local resolver. However, the Android system does not provide such a local resolver, resulting in a connection get refused when attempting to query DNS from [::1]:53.

To resolve this issue, we need to set up a DNS proxy that listens on port 53. You can do this by executing the following command with root privileges:

sudo cloudflared proxy-dns --port 53

Afterwards, open a new terminal and run the tunnel command:

cloudflared tunnel --url ...

These should resolve the problem. Note that setting up a DNS proxy on port 53 requires root privileges.

Jak2k commented 5 months ago

I encountered the same problem and, after some research, I found a solution. Essentially, many Linux distributions include a local resolver that listens on [::1]:53. This resolver is responsible for forwarding DNS queries to the actual DNS server and caching the responses. Cloudflared attempts to query its edge server's IP address by sending a DNS query to the local resolver. However, the Android system does not provide such a local resolver, resulting in a connection get refused when attempting to query DNS from [::1]:53.

To resolve this issue, we need to set up a DNS proxy that listens on port 53. You can do this by executing the following command with root privileges:

sudo cloudflared proxy-dns --port 53

Afterwards, open a new terminal and run the tunnel command:

cloudflared tunnel --url ...

These should resolve the problem. Note that setting up a DNS proxy on port 53 requires root privileges.

Making that local DNS server doesn't work on android with termux.

Liquorice10113 commented 5 months ago

I encountered the same problem and, after some research, I found a solution. Essentially, many Linux distributions include a local resolver that listens on [::1]:53. This resolver is responsible for forwarding DNS queries to the actual DNS server and caching the responses. Cloudflared attempts to query its edge server's IP address by sending a DNS query to the local resolver. However, the Android system does not provide such a local resolver, resulting in a connection get refused when attempting to query DNS from [::1]:53. To resolve this issue, we need to set up a DNS proxy that listens on port 53. You can do this by executing the following command with root privileges: sudo cloudflared proxy-dns --port 53 Afterwards, open a new terminal and run the tunnel command: cloudflared tunnel --url ... These should resolve the problem. Note that setting up a DNS proxy on port 53 requires root privileges.

Making that local DNS server doesn't work on android with termux.

Do you have root though?

Jak2k commented 5 months ago

I dont't have root, but are in the process of rooting with magisk.

Liquorice10113 commented 5 months ago

I dont't have root, but are in the process of rooting with magisk.

Root/sudo is required to bind any port<1024. I am surprised termux team hasn't fix this dns issue by now.

Jak2k commented 5 months ago

I'm using root

ikhwanperwira commented 5 months ago

Try this (no root previleges required), I assume pip is already installed.

pip install udocker
udocker run ikhwanperwira/ucloudflared:latest tunnel --hello-world

To use credential login and make it persistent synchronous between host and container, use -v volume flag. This will mapping ~ (home host) to /home/nonroot (home container)

udocker run -v ~:/home/nonroot ikhwanperwira/ucloudflared:latest tunnel --config=/home/nonroot/cf/config.yaml run

Don't forget update credentials path of config.yaml in credentials-file=/home/nonroot/.cloudflared/<tunnel_id>.json

============================

Explanation:

Inspired from @Liquorice10113 answer, linux cloudflared binary tries to read /etc/hosts for metric (localhost lookup) and /etc/resolv.conf to resolve DNS. It's not possible for non-rooted android to listen on port 53 generally port less than 1024. Therefore I isolate cloudflared with docker. The image was built from this simple Dockerfile:

# Official Cloudflared image
FROM cloudflare/cloudflared:latest

# You can replace `resolv.conf` with `/data/data/com.termux/files/usr/etc/resolv.conf`
COPY resolv.conf /etc/resolv.conf

# You can replace 'hosts` with `/data/data/com.termux/files/usr/etc/hosts`
COPY hosts /etc/hosts

In my cases, resolv.conf using Google DNS

nameserver 8.8.8.8

And hosts:

127.0.0.1 localhost

Then I built the image into specific architecture (linux/arm64) since Android using arm64 with GCP.

docker build --platform linux/arm64 -t ikhwanperwira/ucloudflared:latest . && docker push ikhwanperwira/ucloudflared:latest