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

ss-redir doesn't relay IPv6 UDP packets #2600

Closed
kuangniu opened this issue Jan 19, 2020 · 1 comment
Closed

ss-redir doesn't relay IPv6 UDP packets #2600

kuangniu opened this issue Jan 19, 2020 · 1 comment
Labels

Comments

@kuangniu
Copy link

kuangniu commented Jan 19, 2020

Starting from version 3.3.0, ss-redir seems not be able to relay IPv6 UDP packets, at least on linux.

I have this socksified-router testing setup.

                +- ssrt --------+                                   +- cl ------------------+
           eth0 | bind9         | eth1                         eth0 | gateway 192.0.2.1     |
Internet -------+ ss-server     +-----------------------------------+ gateway 2001:db8::1   |
                | ss-redir*2    | 192.0.2.1/24         192.0.2.2/24 | nameserver 192.0.2.1  |
                |               | 2001:db8::1/64     2001:db8::2/64 | nameserver 2001:db8::1|
                +---------------+                                   +-----------------------+

Machine ssrt have basic iptables/ip-rule setup, where IPv4 TCP, IPv4 UDP and IPv6 TCP relaying works fine. But when I try IPv6 nslookup on cl, it fails.

root@cl:~$ nslookup www.google.com 2606:4700:4700::1111
;; connection timed out; no servers could be reached

ss-redir process (for the IPv6) on ssrt shows following message:

 2020-01-19 14:08:24 INFO: [udp] server receive a packet
 2020-01-19 14:08:24 INFO: [22323] [udp] cache miss: 2606:4700:4700::1111:53 <-> 2001:db8::2:33580
 2020-01-19 14:08:24 INFO: [udp] remote receive a packet
 2020-01-19 14:08:24 ERROR: [udp] remote_recv_bind: Cannot assign requested address

which suggests bind(2) in remote_recv_cb() (udprelay.c; around line 850) failed.

    if (bind(src_fd, (struct sockaddr *)&dst_addr, remote_dst_addr_len) != 0) {
        ERROR("[udp] remote_recv_bind");
        close(src_fd);
        goto CLEAN_UP;
    }

The real problem lies in several lines earlier in the same function.

    int opt = 1;
    int sol = remote_ctx->src_addr.ss_family == AF_INET6 ? SOL_IPV6 : SOL_IP;
    if (setsockopt(src_fd, sol, IP_TRANSPARENT, &opt, sizeof(opt))) {

This executes setsockopt(src_fd, SOL_IPV6, IP_TRANSPARENT, ...) in case of IPv6, which actually does setsockopt(src_fd, SOL_IPV6, IPV6_MULTICAST_LOOP, ...), because IP_TRANSPARENT is not an option for SOL_IPV6.

This fails to set TRANSPARENT option for the socket, thus bind(2) fails to bind an foreign address.

The correct way would be either:
setsockopt(src_fd, SOL_IP, IP_TRANSPARENT, ...) (which works for IPv6 sockets anyway)
or
setsockopt(src_fd, SOL_IPV6, IPV6_TRANSPARENT, ...) (in case of IPv6 sockets).

What version of shadowsocks-libev are you using?

This issue affects from v3.3.0 to current.

What operating system are you using?

I tested on Ubuntu Bionic and Eoan.

What did you do?

What did you expect to see?

What did you see instead?

see above.

What is your config in detail (with all sensitive info masked)?

I don't think you need configurations for this case. Let me know if you didn't reproduce the issue.

Am I the only one who uses IPv6 UDP relaying?

@madeye
Copy link

madeye commented Jan 19, 2020

Thanks for catching this issue. A pull request should be better.

@madeye madeye added the bug label Jan 19, 2020
@madeye madeye closed this as completed in 4f577a0 Jan 19, 2020
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

2 participants