shadowsocks / shadowsocks-org

www.shadowsocks.org
MIT License
890 stars 548 forks source link

[SIP009] Handling remote DNS in ss-server in a backwards compatible way #156

Open Mygod opened 4 years ago

Mygod commented 4 years ago

I propose that if shadowsocks server receives a (TCP/UDP) connection to 0.0.0.0:53 or [::]:53, it should redirect the connection to current default DNS resolver (on Linux, this might be handled by res_query). This is useful for socksifier VPNs ~as well as resolving ACL rules~.

This is a backwards compatible change and should not break anything. (maybe this is an SIP?)

ghost commented 4 years ago

0.0.0.0:53

Literally 0.0.0.0 (0.0.0.0/32) or just any IP address (0.0.0.0/0)?

riobard commented 4 years ago

SOCKS6 draft RFC section 12 has some idea I think we should probably borrow. However this should be made optional since it has security implications.

Mygod commented 4 years ago

@studentmain 32.

@riobard Damn it someone already had that idea before me. But yeah we might want to look into SOCKS6 more.

riobard commented 4 years ago

I'm modeling v2 protocol upon SOCKS6 but it's still draft so changes are to be expected.

ghost commented 4 years ago

I think this is an SIP. Client built in DNS proxy (we can't send to 0.0.0.0 on socket) will required to use this feature.

riobard commented 4 years ago

If there's a dns resolver running on the server (e.g. dnsmasq), wouldn't the client be able to use it just by connecting to 127.0.0.1:53?

Mygod commented 4 years ago

Added [SIP] to title as per discussions.

@riobard I made a pass through the socks6 draft. I think we can extend shadowsocks to v2 to accommodate socks6 when the rfc goes stable.

riobard commented 4 years ago

Right, that's why I'm modeling the v2 on SOCKS6 now.

fortuna commented 4 years ago

The Outline team has also discussed some ideas on how to make the server define the DNS resolver to be used.

Alternative 1: use a special domain name (e.g. dns.local.) One alternative we discussed was to have a special hostname. For example, dns.local, and then make sure we use the hostname address (not IP) in the SS header.

Alternative 2: use :53 as the DNS resolver An alternative is for the client to assume :53 is a DNS resolver. We can run a forwarder resolver there and set the firewall so that it doesn't accept external connections.

In any of those cases, the client needs to check if the functionality is available first.

One thing that bothers me with 0.0.0.0, is that it's usually interpreted as any IP on an interface. So we're mixing up the semantics

cc: @alalamav @bemasc

Mygod commented 4 years ago

@fortuna 0 address is also used in socks6 draft and we really do mean any address so I think it's fine. Of course this behavior will only be used for TCP/UDP connect.

EDIT: I think in the case of Outline where the server is entirely managed, I think the alternatives you propose would work fine. In general, we want a shadowsocks server to coexist with other thing and we don't want to take out bind :53 (systemd-resolved is absolutely disgusting) nor a hostname.

bemasc commented 4 years ago

The SOCKS 6 draft, and especially this DNS support proposal, are still early in the IETF review process. Ultimately, I trust the IETF to choose whether this is an acceptable use of 0.0.0.0 or not. If not, it could be implemented using a new IANA-reserved domain like socks-server.arpa, or using a new (fourth) address type (not IPv4, IPv6, or domain).

Mygod commented 4 years ago

@bemasc Using a 4th address type is a good idea actually...

Mygod commented 4 years ago

@bemasc On second thought, I think the issue is that we want to support both DNS over TCP and UDP, so this actually ends up using two more address types (DNS over TCP, DNS over UDP). Also maybe the IP address could also serve as a hint (meaning not requirement) for server to either use an IPv4/IPv6 DNS?

ghost commented 4 years ago

DNS over TCP and UDP

SS client act as a DNS proxy here, so I think only support DNS over TCP is ok.

fortuna commented 4 years ago

I wonder if a better option is to define a new SOCKS command. Why overload the existing commands (CONNECT), and make their implementations more complicated, if you can have a new command that can isolate complexity (e.g. RESOLVE)?

Connecting and resolving are different operations, so you can expect different parameters. A new command would allow that, rather than overloading and abusing the existing CONNECT parameters, which will make the protocol harder to understand and maintain.

ghost commented 4 years ago

I wonder if a better option is to define a new SOCKS command. Why overload the existing commands (CONNECT), and make their implementations more complicated, if you can have a new command that can isolate complexity (e.g. RESOLVE)?

Connecting and resolving are different operations, so you can expect different parameters. A new command would allow that, rather than overloading and abusing the existing CONNECT parameters, which will make the protocol harder to understand and maintain.

Current SS protocol has no SOCKS command field...

But it's good idea for SOCKS6 protocol (maybe SS v2 protocol too).

Mygod commented 4 years ago

@fortuna I think there are some advantages for using the zero address. In practice, connecting to zero address is equivalent to connecting to localhost, so even if the socks server is not implemented correctly (or simply not updated to support this), it is easily fixable by setting up another DNS relay/server at localhost:53.

@madeye If it looks good, shall we assign it a number and start implementing it? (e.g. https://github.com/shadowsocks/shadowsocks-android/commit/3a7ab2217925af145b54620cf665d85623a23280)

madeye commented 4 years ago

I think we can first implement it in shadowsocks-rust as an experimental feature.

kimw commented 4 years ago

I wonder if a better option is to define a new SOCKS command. Why overload the existing commands (CONNECT), and make their implementations more complicated, if you can have a new command that can isolate complexity (e.g. RESOLVE)?

A non-standard SOCKS command may expose the shadowsocks. I mean, for example, any bad APP can try the command (e.g. RESOLVE).

ghost commented 4 years ago

I wonder if a better option is to define a new SOCKS command. Why overload the existing commands (CONNECT), and make their implementations more complicated, if you can have a new command that can isolate complexity (e.g. RESOLVE)?

A non-standard SOCKS command may expose the shadowsocks. I mean, for example, any bad APP can try the command (e.g. RESOLVE).

If an app can try SOCKS command, it already know the server password.

kimw commented 4 years ago

If an app can try SOCKS command, it already know the server password.

@studentmain Not at all. The APP, which trying to make connections thru SOCKS, only knows about: there's a SOCKS proxy service, a common IT infrastructure.

ghost commented 4 years ago

If an app can try SOCKS command, it already know the server password.

@studentmain Not at all. The APP, which trying to make connections thru SOCKS, only knows about: there's a SOCKS proxy service, a common IT infrastructure.

Then it exposed shadowsocks client (again, but with a hard way), not server. And current shadowsocks protocol itself has no SOCKS command field.

kimw commented 4 years ago

Then it exposed shadowsocks client (again, but with a hard way), not server. And current shadowsocks protocol itself has no SOCKS command field.

Yes, it is. The ss-server, ss-tunnel, and ss-redir will never exposed, but only ss-local do (if ss-local implements custom SOCKS command).