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

Support multiple server addresses correctly in ss-local #942

Open
Mygod opened this issue Nov 12, 2016 · 18 comments
Open

Support multiple server addresses correctly in ss-local #942

Mygod opened this issue Nov 12, 2016 · 18 comments

Comments

@Mygod
Copy link

Mygod commented Nov 12, 2016

According to local.c#1032, ss-local will attempt to use a random remote address when multiple server addresses are supplied and use the first one as UDP relay.

When a hostname is supplied, according to netutils.c#L170, ss-local will try to resolve it and PREFER IPv4 addresses.

This could bring issues when it's used under an IPv6-only environment when both IPv4/IPv6 server address is supplied or a hostname with both A and AAAA record.

According to here, here's how Chrome does it:

When a hostname has both IPv6 and IPv4 addresses, and the IPv6 address is listed first, we start a timer (300ms) (deliberately chosen to be different from the backup connect job). If the timer fires, that means the IPv6 connect() hasn't completed yet, and we start a second socket connect() where we give it the same AddressList, except we move all IPv6 addresses that are in front of the first IPv4 address to the end. That way, we will use the first IPv4 address. We will race these two connect()s and pass the first one to complete to ConnectJob::set_socket().

Maybe we could use the same/similar mechanism here.

  1. Hostnames are expanded to all A/AAAA records in it, remaining its original order;
  2. Try to connect to all the servers in order with 300ms timeout (perhaps configurable?). After timeout the next address is tried in parallel with another 300ms timeout. The fastest one will be picked. However if the next address is an IPv6 address while the current address is IPv4, the next one is tried in parallel immediately without timeout. (preference for IPv6)
  3. After the connection is established, the address used will be marked as fastest. On the next connection, this fastest address will be tried first, then all the other addresses in order after a 300ms timeout.
@madeye
Copy link

madeye commented Nov 12, 2016

I prefer to adding a -6 option to resolve IPv6 address first. Then you can run multiple ss-local instances simultaneously with port reuse.

@Mygod
Copy link
Author

Mygod commented Nov 12, 2016

I don't really get that.

@madeye
Copy link

madeye commented Nov 12, 2016

Running multiple ss-local instances like this:

ss-local -c config.json -l 1080 -s s1.test.com
ss-local -c config.json -l 1080 -s s1.test.com -6

It means to connect IPv4 and IPv6 addresses separately and let OS perform the load balance [1].

[1] https://lwn.net/Articles/542629/

madeye added a commit that referenced this issue Nov 12, 2016
@Mygod
Copy link
Author

Mygod commented Nov 12, 2016

I didn't know that was possible. I tried this: (background running another ss-local connecting to ipv6 address)

$ ss-local -c config-ipv4.json -l 1080
 2016-11-12 11:01:34 INFO: onetime authentication enabled
 2016-11-12 11:01:34 INFO: initializing ciphers... chacha20
 2016-11-12 11:01:34 INFO: tcp port reuse enabled
 2016-11-12 11:01:34 ERROR: listen() error
$

@Mygod
Copy link
Author

Mygod commented Nov 12, 2016

As that article points out:

SO_REUSEPORT distributes datagrams evenly across all of the receiving threads.

I'm not actually going for load balancing. It's about making it work in both IPv4-only and IPv6-only environments (or in different subnets) without reconfiguration.

If it's for load balancing, the random pick would be fine.

@madeye
Copy link

madeye commented Nov 12, 2016

I think it would be hard for shadowsocks-libev to do this. My suggestion is to involve HAProxy here to do the failover.

@debiansid
Copy link

How about mptcp?

@Mygod
Copy link
Author

Mygod commented Nov 12, 2016

Doesn't sound too hard. You just need to make some parallel connections.

@madeye
Copy link

madeye commented Nov 12, 2016

Maybe you can help to implement this? BTW, I still recommend to use haproxy instead.

@Mygod
Copy link
Author

Mygod commented Nov 12, 2016

Actually I wish to use this feature on shadowsocks-android (currently my WLAN is IPv6-only and mobile data is IPv4-only) so haproxy might not be as desirable.

I'm not sure what's the best way to implement this in shadowsocks-libev. It'll probably take me longer to implement this. 😜

@madeye
Copy link

madeye commented Nov 12, 2016

I have to say dual stack is really a disaster. Let's keep this issue open, maybe oneday I can figure out a easy way to implement this.

@vfreex
Copy link

vfreex commented Nov 14, 2016

I think the more generic (but slower) way is to keep all IPv4 & IPv6 addresses of the domain name and iterate over all the addresses one by one until you find the correct one that can be connected, because there's no guarantee that all addresses are working.

@marcovillar
Copy link

I am not sure if its the same subject, but i was wondering is it possible to add multipliable ss servers
in the config and do some kind of loadbalancing or best performance for the reason of anti detection
by the gfw.

@cherrot
Copy link

cherrot commented Mar 6, 2017

(I don't know if it is appropriate to ask in this thread.)

I want to know why the --reuse-port option is switched off by default in some newer version of shadowsocks? After all there is no bad effect for normal use.

FYI, I'm using shadowsocks-libev 3.0.2-1 on archlinux.

@tenwx
Copy link

tenwx commented Feb 23, 2018

Please support ipv6 fallback to ipv4.
Test url: http://fallback-v6.ipv6-test.com/json/proto.php

  • Visit directly with curl on server I got
    ({"address":"63.223.1.1","protocol":"4"})
  • client browser using a SOCKS5 proxy created by ssh -D, got
    ({"address":"63.223.1.1","protocol":"4"})
  • client browser using a SOCKS5 proxy created by ss-local, got
    ERR_EMPTY_RESPONSE

ss version 3.1.0 on linux

@Mygod
Copy link
Author

Mygod commented Feb 23, 2018

@tenwx That should be implemented by browsers and I can't reproduce the behavior you reported either.

@tenwx
Copy link

tenwx commented Feb 23, 2018

@Mygod No, it depends on ss-server behavior. It can be reproduced.
Your situation I guess is due to your server does not support ipv6.
dig fallback-v6.ipv6-test.com any

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.el6_9.4 <<>> fallback-v6.ipv6-test.com any
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12238
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;fallback-v6.ipv6-test.com.     IN      ANY

;; ANSWER SECTION:
fallback-v6.ipv6-test.com. 119  IN      A       5.135.165.173
fallback-v6.ipv6-test.com. 119  IN      AAAA    2001:41d0:8:e8ad::fa11:bac

;; Query time: 103 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Feb 23 15:00:21 2018
;; MSG SIZE  rcvd: 87

@debiansid
Copy link

Actually , this feature is very useful when you need distribute the traffic to different ss-server.

I would like this

server_address 1 = 1.2.3.4 local_port 1 =1234
server_address 2 = 5.6.7.8 local_port 2 =5678

for ss-redir , then iptables will redirect local traffic into different local port.

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

No branches or pull requests

7 participants