diff --git a/.gitignore b/.gitignore index e1d5051a..8ab41791 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,4 @@ doc/*.html # Visual Studio Code .vscode/* +.devcontainer/* diff --git a/src/udprelay.c b/src/udprelay.c index 580ad4bd..5de38830 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -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);