Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shadowsocks doesn't tunnel DNS queries through UDP proxy #2670

Closed
6 of 17 tasks
khashmeshab opened this issue Jan 28, 2021 · 20 comments
Closed
6 of 17 tasks

Shadowsocks doesn't tunnel DNS queries through UDP proxy #2670

khashmeshab opened this issue Jan 28, 2021 · 20 comments
Labels

Comments

@khashmeshab
Copy link

khashmeshab commented Jan 28, 2021

Please read contributing guidelines. Thanks.

Describe the bug
In Iran, the ISP's inspect and manipulate DNS queries. Even if you send the request to say 1.1.1.1, they respond on behalf of 1.1.1.1, with their own blocked IP address, which is 10.10.34.35. I tested and saw that while the "Remote DNS" option exists in Shadowsocks on Android, it doesn't get tunnelled through the proxy. So, you wouldn't able to access the blocked websites without having their IP addresses, even if your Shadowsocks VPN is on.

To Reproduce
Steps to reproduce the behavior:

  1. Be in Iran (or any other DNS manipulating country)
  2. Turn your Shadowsocks Android on, with "Remote DNS" option set to an open international server.
  3. Open a blocked website (preferably without HTTPS to be able to see the "blocked" page).
  4. See the "blocked" page.
  5. Alternatively, you can ping the website name and see that it resolves to 10.10.34.35.

Expected behavior
DNS queries should be proxied through the UDP proxy, and blocked domains should get resolved to their original IP addresses. Websites should open.

Screenshots
If applicable, add screenshots to help explain your problem.

Smartphone (please complete the following information):

  • Android/Chrome OS version: Android 10 QKQ1.191215.002 MIUI Global 12.0.2 Stable QJZMIXM
  • Device: Xiaomi Redmi Note 9 Pro
  • Version: 5.2.1
  • Last version that did not exhibit the issue: [not applicable]

Configuration
Put an x inside the [ ] that applies.

  • IPv4 server address
  • IPv6 server address
  • Client IPv4 availability
  • Client IPv6 availability
  • Encrypt method:
  • Route
    • All
    • Bypass LAN
    • Bypass China
    • Bypass LAN & China
    • GFW List
    • China List
    • Custom rules
  • IPv6 route
  • Apps VPN mode
    • Bypass mode
  • Remote DNS: 8.8.8.8
  • DNS over UDP (Does not exist)
  • Plugin configuration (if applicable):
  • Auto Connect
  • TCP Fast Open
  • If you're not using VPN mode, please supply more details here:

Additional context
Add any other context about the problem here.

@khashmeshab
Copy link
Author

A wild guess would be it's somehow related to fixing #2301. BTW why there's no "DNS over UDP" option anymore?

@khashmeshab
Copy link
Author

So, I did this. I exported all my profiles to profiles.json. Then opened it on a computer, and replaced all '"udpdns": false' to '"udpdns": true'. Then used 'Replace from file' menu item in Shadowsocks Android, and it seems to fix the issue. Why did you remove the 'DNS over UDP' option?

@madeye
Copy link
Contributor

madeye commented Jan 29, 2021

It's expected. Remote DNS over UDP is not supported anymore.

@madeye madeye removed the bug label Jan 29, 2021
@khashmeshab
Copy link
Author

It still exists in Shadowsocks Android, because I could use it just by replacing the udpdns from false to true in the json file. You just removed the option to toggle it on. It'd be easy to take it back on, and we Iranians would be able to have a secure tunnel. Also, tunneling DNS through a secure channel like Shadowsocks would disallow ISP and governments to monitor people, even if they don't manipulate the result.

@madeye
Copy link
Contributor

madeye commented Jan 29, 2021

Remote DNS over TCP is still supported.

So don't worry about it, just make sure the remote DNS you're using support TCP protocol. Any public DNS resolvers should support TCP DNS queries.

@khashmeshab
Copy link
Author

So, dns.google supports DNS over TCP? Then why I received 10.10.34.35 for a blocked website, with the default configuration? Should I record a video for you to believe that something doesn't work right?

And I don't understand why remove a feature that's already there, sitting there without hurting anybody? Why tunnel all UDP traffic, and only exclude the traffic to the DNS server on port 53?

@madeye
Copy link
Contributor

madeye commented Jan 29, 2021

You're bypassing LAN IPs, that's the root cause. 10.10.34.35 is a LAN IP, that's why the domain name is resolved by the local resolver rather than the remote one.

There're two solutions:

  1. Try custom rules, make sure the blocked domain name is added in your list.
  2. Use All routing.

@khashmeshab
Copy link
Author

So, if I understand it correctly, you're saying that Shadowsocks first resolves any domain locally, then if it receives its IP address in localnet range, then it stops. But if it wasn't, it then resolves it with the 'Remote DNS' via TCP and uses that IP address. I don't know how to say it respectfully, but that's nonsense. That's a security hole! That's also not correct and it's illogical. How on earth does Shadowsocks know that a domain resolves to a localnet address, so it use a local DNS resolver before actually resolving it? And why this never happened with DNS over UDP?

Look, my problem is not that 10.10.34.35 is not tunnelled through Shadowsocks. It's what I expect by selecting "Bypass LAN". The problem is that domains shouldn't get resolved through Iranian manipulative DNS servers and they should get resolved by the DNS server I set, and they should go through the Shadowsocks tunnel. Is it wrong and illogical?

Is it too much to ask to take back the "DNS over UDP" option and set it to off by default?

@madeye
Copy link
Contributor

madeye commented Jan 29, 2021

It's not a security hole but expected behavior, since you're using Bypass LAN routing policy. See #2664 for more details.

For your use case, I suggest create a custom ACL following this example: https://github.com/ACL4SSR/ACL4SSR/blob/master/fullgfwlist.acl

@madeye
Copy link
Contributor

madeye commented Jan 29, 2021

BTW, enabling private DNS in your Android system would also solve your problem.

@khashmeshab
Copy link
Author

First, enabling Private DNS in Android would break my connection when Shadowsocks is not connected. Because all DNS over HTTPS servers are also blocked. So, I'd need to toggle it off and on every time I connect and disconnect to SS.

But please tell me if I understand it correctly: Say I open xxx.com, a blocked website. Shadowsocks first queries my local (manipulative) DNS server, which would return 10.10.34.35, because it's blocked. Then since I selected "Bypass LAN", it wouldn't use remote DNS. If the website wasn't blocked and returned a public IP address, then it queries the remote DNS for its IP address.

In this case, what's the use of the "Remote DNS" option? And wouldn't my local DNS datamine all websites I visit? All and all, you still didn't answer why this doesn't happen with DNS over UDP?

If you think that I say dns.google resolves to 10.10.34.35, it's not correct. dns.google correctly resolves to 8.8.8.8, which is not in localnet. So, it must be tunnelled through Shadowsocks, which is not, when DNS over UDP is turned off.

Please for a moment think that maybe this is an actual bug. I'm a software developer for 24 years and I know what I'm talking about. There's something wrong in the code which toggling DNS over UDP would cause it to not tunnel connections to the remote DNS server port 53 (TCP and UDP) to go through Shadowsocks. Just take back the DNS over UDP option and we're good!

@madeye
Copy link
Contributor

madeye commented Jan 29, 2021

The behavior you described here is only related to Bypass LAN routing. Try GFW List or your custom list, any domain name listed in that ACL would be only resolved by the remote resolver.

Imaging you're using the device in a company network, for any internal website, the domain name should be resolved by the local DNS. And that's why we first resolve domains with local resolver in Bypass LAN mode.

@khashmeshab
Copy link
Author

Why this automatically resolves when DNS over UDP?

And is it too much work to get the DNS over UDP option back?

This certainly doesn't work for me. If custom rules had a "Bypass" option, I'd add localnet to it and omit all the local resolving nonsense. So, I may need to fork the code and compile my own version for personal use.

@madeye
Copy link
Contributor

madeye commented Jan 29, 2021

DNS over UDP is something broken for years, as we didn't support policy routing for UDP before. And that's actually why you found all the UDP DNS queries are forwarded to the remote server in the previous versions.

Now that we moved to shadowsocks-rust and have much better policy based DNS solution, it's not necessary to control DNS over UDP anymore.

Fork is always welcome. We cannot meet every feature request, but if forking works for you, it'd be a really good option.

BTW, a custom ACL is very easy for your case. You just need this ACL:

[bypass_all]

[proxy_list]
#Proxy all and all the domain names will be resolved with the remote resolver.
^.*$

@khashmeshab
Copy link
Author

khashmeshab commented Jan 29, 2021

Please verify if I understand it now. So, every UDP packet gets tunnelled through Shadowsocks, except DNS packets to remote DNS port 53. Those packets get through a process. If "Bypass LAN" is selected, first the local resolver is used and if it pointed to a localnet IP address, then the address is used and get bypassed. If not, the remote DNS is used over TCP (why not UDP? it's certainly faster.) to get the IP address. If I unselect "Bypass LAN", the local resolver wouldn't get used at all?

My problem is that if I select custom rules, it'd be a mess to set "IP addresses other than localnet" in custom rules. Something like this:

0.0.0.0/5, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/2, 128.0.0.0/3, 160.0.0.0/5, 168.0.0.0/6, 172.0.0.0/12, 172.32.0.0/11, 172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, 176.0.0.0/4, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, ::/0

which is equal to anything other than localnet. And I don't know how to use your proposed ACL. Where should I enter it? Will it bypass localnet IP addresses without querying local DNS resolver?

@madeye
Copy link
Contributor

madeye commented Jan 29, 2021

If I unselect "Bypass LAN", the local resolver wouldn't get used at all?

Right.

You don't need to specify the IP range.
The ACL file I provided above means any domain name would be proxied. It's domain name based rules.

In the custom rule view, you can add this rule directly.

@khashmeshab
Copy link
Author

Just to make sure, it would also bypass localnet IP addresses? I guess every direct request to IP addresses without a domain name would get bypassed?

Should I select "Manual Settings" or "Import from Clipboard". I selected "Import from Clipboard" and only the last line appeared.

@madeye
Copy link
Contributor

madeye commented Jan 29, 2021

Manually adding .* as a regex should be fine.

@khashmeshab
Copy link
Author

Okay. I'd rather go with my own "IP ranges other than localnet" rule, since that way, it'd also proxy all connections to outside world even without a domain name, and only bypasses localnet.

To sum up my suggestions:

  • Do DNS resolutions over UDP. It's certainly faster with lower overhead. There's a reason people chose it as the default DNS resolving protocol.
  • I use Shadowsocks for 8 years and never knew that "Bypass LAN" uses local resolver first. My government knows everything about me! So, please add a warning and explain it to users.
  • Add another option named "Bypass LAN without using local DNS" to profiles for people like me who just need to bypass local IP addresses, not domain names.
  • Add another option named "Bypass custom rules" to profiles to bypass anything in custom rules and proxy everything else. This way, adding subnets to bypass or Iranian domains would be much easier.

Afterall, thank you for creating Shadowsocks, and for years and years of Internet freedom. I own 7 personal Shadowsocks proxies all over the world. I use a RasPi in my home as WiFi access point and I configured it to bypass all local and Iranian IP addresses and automatically TPROXY everything else through Shadowsocks. And there's no government censorship anymore!

@database64128
Copy link

Using local DNS resolver should be an explicit option instead of an implicit behavior behind "Bypass LAN", which most people including myself assume was to simply route traffic to private IP addresses for direct connection.

We can almost certainly assume that the local DNS at the user's end exhibits malicious behaviors. In my opinion, the local resolver should only be used to resolve hostnames in Shadowsocks server addresses. It must not be used when the user is connected to a Shadowsocks server.

I also support using UDP for DNS by default. Maybe keep an option for those who prefer to use TCP for plain DNS for whatever reason that only makes sense to themselves.

I can't believe people are still running TCP only Shadowsocks servers. And I'm starting an issue to draft an amendment that adds UDP to SIP003.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants