mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-30 13:13:44 +00:00
Redir UDP send back sockets should always be IPv6
ref shadowsocks/shadowsocks-rust#855 When receiving UDP packets from remote servers, Redir will have to create transparent sockets to bind() on those target addresses and then relay data back to the local client. Target addresses may be IPv4 or IPv6 addresses, so we may have to create that transprent sockets based on the target addresses' family. The most simpliest and easiest way is to always create IPv6 sockets and converts IPv4 binding addresses and peer addresses to IPv4-mapped-IPv6.
This commit is contained in:
@@ -97,3 +97,4 @@ doc/*.html
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
.devcontainer/*
|
||||
|
||||
+36
-8
@@ -743,6 +743,29 @@ resolv_cb(struct sockaddr *addr, void *data)
|
||||
|
||||
#endif
|
||||
|
||||
void convert_ipv4_mapped_ipv6(struct sockaddr_storage* addr) {
|
||||
if (addr->ss_family == AF_INET) {
|
||||
struct sockaddr_in* ipv4_addr = (struct sockaddr_in*)addr;
|
||||
|
||||
struct sockaddr_storage mapped_addr;
|
||||
memset(&mapped_addr, 0, sizeof(mapped_addr));
|
||||
|
||||
struct sockaddr_in6* mapped_ipv6_addr = (struct sockaddr_in6*)&mapped_addr;
|
||||
mapped_ipv6_addr->sin6_family = AF_INET6;
|
||||
mapped_ipv6_addr->sin6_port = ipv4_addr->sin_port;
|
||||
uint8_t* ipv6_raw_addr = mapped_ipv6_addr->sin6_addr.s6_addr;
|
||||
ipv6_raw_addr[10] = 0xff;
|
||||
ipv6_raw_addr[11] = 0xff;
|
||||
in_addr_t ipv4_raw_addr = ntohl(ipv4_addr->sin_addr.s_addr);
|
||||
ipv6_raw_addr[12] = (ipv4_raw_addr >> 24) & 0xff;
|
||||
ipv6_raw_addr[13] = (ipv4_raw_addr >> 16) & 0xff;
|
||||
ipv6_raw_addr[14] = (ipv4_raw_addr >> 8) & 0xff;
|
||||
ipv6_raw_addr[15] = ipv4_raw_addr & 0xff;
|
||||
|
||||
memcpy(addr, &mapped_addr, sizeof(mapped_addr));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
remote_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
{
|
||||
@@ -858,21 +881,19 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
}
|
||||
|
||||
size_t remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&remote_ctx->src_addr);
|
||||
|
||||
#ifdef MODULE_REDIR
|
||||
convert_ipv4_mapped_ipv6(&dst_addr);
|
||||
|
||||
size_t remote_dst_addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr);
|
||||
|
||||
int src_fd = socket(remote_ctx->src_addr.ss_family, SOCK_DGRAM, 0);
|
||||
int src_fd = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
if (src_fd < 0) {
|
||||
ERROR("[udp] remote_recv_socket");
|
||||
goto CLEAN_UP;
|
||||
}
|
||||
int opt = 1;
|
||||
int sol = remote_ctx->src_addr.ss_family == AF_INET6 ? SOL_IPV6 : SOL_IP;
|
||||
int flag = remote_ctx->src_addr.ss_family == AF_INET6 ? IPV6_TRANSPARENT : IP_TRANSPARENT;
|
||||
if (setsockopt(src_fd, sol, flag, &opt, sizeof(opt))) {
|
||||
int opt = 1;
|
||||
if (setsockopt(src_fd, SOL_IPV6, IPV6_TRANSPARENT, &opt, sizeof(opt))) {
|
||||
ERROR("[udp] remote_recv_setsockopt");
|
||||
close(src_fd);
|
||||
goto CLEAN_UP;
|
||||
@@ -889,7 +910,7 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
#ifdef IP_TOS
|
||||
// Set QoS flag
|
||||
int tos = 46 << 2;
|
||||
int tos = 46 << 2;
|
||||
int rc = setsockopt(src_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
|
||||
if (rc < 0 && errno != ENOPROTOOPT) {
|
||||
LOGE("setting ipv4 dscp failed: %d", errno);
|
||||
@@ -907,8 +928,14 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
goto CLEAN_UP;
|
||||
}
|
||||
|
||||
struct sockaddr_storage mapped_src_addr;
|
||||
memcpy(&mapped_src_addr, &remote_ctx->src_addr, sizeof(remote_ctx->src_addr));
|
||||
convert_ipv4_mapped_ipv6(&mapped_src_addr);
|
||||
|
||||
size_t remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&mapped_src_addr);
|
||||
|
||||
int s = sendto(src_fd, buf->data, buf->len, 0,
|
||||
(struct sockaddr *)&remote_ctx->src_addr, remote_src_addr_len);
|
||||
(struct sockaddr *)&mapped_src_addr, remote_src_addr_len);
|
||||
if (s == -1 && !(errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
ERROR("[udp] remote_recv_sendto");
|
||||
close(src_fd);
|
||||
@@ -917,6 +944,7 @@ remote_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
close(src_fd);
|
||||
|
||||
#else
|
||||
size_t remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&remote_ctx->src_addr);
|
||||
|
||||
int s = sendto(server_ctx->fd, buf->data, buf->len, 0,
|
||||
(struct sockaddr *)&remote_ctx->src_addr, remote_src_addr_len);
|
||||
|
||||
Reference in New Issue
Block a user