From c5c8e5ebaf62f2ac11f2d33bc12f8a93f383b61e Mon Sep 17 00:00:00 2001 From: Max Lv Date: Wed, 14 Oct 2026 15:46:07 +0800 Subject: [PATCH] Fix the build with GCC and libstdc++ crypto.h's min/max macros broke in C++ sources that include it first, netutils.h's linux/tcp.h clashed with the netinet/tcp.h libuv includes, and GCC rejects memcpy into crypto_t. Apple clang accepted all three. --- src/crypto.cpp | 6 +- src/crypto.h | 3 + src/manager.cpp | 2 +- src/netutils.h | 8 +- src/redir.h | 86 --- src/stream.cpp | 5 +- src/udprelay.cpp | 1626 ---------------------------------------------- src/udprelay.h | 104 --- 8 files changed, 15 insertions(+), 1825 deletions(-) delete mode 100644 src/redir.h delete mode 100644 src/udprelay.cpp delete mode 100644 src/udprelay.h diff --git a/src/crypto.cpp b/src/crypto.cpp index 70111ce1..13028f63 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -57,7 +57,7 @@ brealloc(buffer_t *ptr, size_t len, size_t capacity) { if (ptr == NULL) return -1; - size_t real_capacity = max(len, capacity); + size_t real_capacity = len > capacity ? len : capacity; if (ptr->capacity < real_capacity) { ptr->data = (char *)ss_realloc(ptr->data, real_capacity); ptr->capacity = real_capacity; @@ -171,7 +171,7 @@ crypto_init(const char *password, const char *key, const char *method) .ctx_init = &stream_ctx_init, .ctx_release = &stream_ctx_release, }; - memcpy(crypto, &tmp, sizeof(crypto_t)); + memcpy((void *)crypto, &tmp, sizeof(crypto_t)); /* const members: copy the bytes */ return crypto; } @@ -200,7 +200,7 @@ crypto_init(const char *password, const char *key, const char *method) .udp_session_release = aead_is_2022(cipher) ? &aead_2022_udp_session_release : NULL, }; - memcpy(crypto, &tmp, sizeof(crypto_t)); + memcpy((void *)crypto, &tmp, sizeof(crypto_t)); /* const members: copy the bytes */ return crypto; } } diff --git a/src/crypto.h b/src/crypto.h index 31c32c92..baab248f 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -69,8 +69,11 @@ typedef mbedtls_md_info_t digest_type_t; #define CRYPTO_NEED_MORE -1 #define CRYPTO_OK 0 +/* Not for C++, where they would break . */ +#ifndef __cplusplus #define min(a, b) (((a) < (b)) ? (a) : (b)) #define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif #define SUBKEY_INFO "ss-subkey" #define IV_INFO "ss-iv" diff --git a/src/manager.cpp b/src/manager.cpp index 7e9494ec..a91591ee 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -1042,7 +1042,7 @@ manager_recv_cb(SS_P_ ss_io *w, int revents) } size_t pos = strlen(buf); - strcpy(buf + max(pos - 1, 1), "\n]"); // Remove trailing "," + strcpy(buf + (pos > 2 ? pos - 1 : 1), "\n]"); // Remove trailing "," pos = strlen(buf); if (sendto(manager->fd, buf, pos, 0, (struct sockaddr *)&claddr, len) != pos) { diff --git a/src/netutils.h b/src/netutils.h index a0b82eb6..3452870a 100644 --- a/src/netutils.h +++ b/src/netutils.h @@ -31,10 +31,12 @@ #include #endif -#if defined(HAVE_LINUX_TCP_H) -#include -#elif defined(HAVE_NETINET_TCP_H) +/* netinet/tcp.h first: libuv includes it, and linux/tcp.h redefines its + * structures. */ +#if defined(HAVE_NETINET_TCP_H) #include +#elif defined(HAVE_LINUX_TCP_H) +#include #elif defined(HAVE_NETDB_H) #include #endif diff --git a/src/redir.h b/src/redir.h deleted file mode 100644 index 8e9af0e6..00000000 --- a/src/redir.h +++ /dev/null @@ -1,86 +0,0 @@ -/* * redir.h - Define the redirector's buffers and callbacks - * - * Copyright (C) 2013 - 2019, Max Lv - * - * This file is part of the shadowsocks-libev. - * - * shadowsocks-libev is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * shadowsocks-libev is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with shadowsocks-libev; see the file COPYING. If not, see - * . - */ - -#ifndef _REDIR_H -#define _REDIR_H - -#include "ss_event.h" - -#include "crypto.h" -#include "jconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct listen_ctx { - ss_io io; - int remote_num; - int timeout; - int fd; - int mptcp; - int tos; - struct sockaddr **remote_addr; -} listen_ctx_t; - -typedef struct server_ctx { - ss_io io; - int connected; - struct server *server; -} server_ctx_t; - -typedef struct server { - int fd; - - buffer_t *buf; - - cipher_ctx_t *e_ctx; - cipher_ctx_t *d_ctx; - struct server_ctx *recv_ctx; - struct server_ctx *send_ctx; - struct remote *remote; - - struct sockaddr_storage destaddr; - ss_timer delayed_connect_watcher; -} server_t; - -typedef struct remote_ctx { - ss_io io; - ss_timer watcher; - int connected; - struct remote *remote; -} remote_ctx_t; - -typedef struct remote { - int fd; - buffer_t *buf; - struct remote_ctx *recv_ctx; - struct remote_ctx *send_ctx; - struct server *server; - uint32_t counter; - struct sockaddr *addr; -} remote_t; - -#ifdef __cplusplus -} -#endif - -#endif // _REDIR_H diff --git a/src/stream.cpp b/src/stream.cpp index 7e221ba0..5e6fd410 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -504,8 +504,9 @@ stream_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity) balloc(cipher_ctx->chunk, cipher->nonce_len); } - size_t left_len = min(cipher->nonce_len - cipher_ctx->chunk->len, - ciphertext->len); + size_t left_len = cipher->nonce_len - cipher_ctx->chunk->len; + if (left_len > ciphertext->len) + left_len = ciphertext->len; if (left_len > 0) { memcpy(cipher_ctx->chunk->data + cipher_ctx->chunk->len, ciphertext->data, left_len); diff --git a/src/udprelay.cpp b/src/udprelay.cpp deleted file mode 100644 index 7dcdff55..00000000 --- a/src/udprelay.cpp +++ /dev/null @@ -1,1626 +0,0 @@ -/* - * udprelay.cpp - Setup UDP relay for both client and server - * - * Copyright (C) 2013 - 2019, Max Lv - * - * This file is part of the shadowsocks-libev. - * - * shadowsocks-libev is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * shadowsocks-libev is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with shadowsocks-libev; see the file COPYING. If not, see - * . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef __MINGW32__ -#include -#include -#include -#include -#include -#endif -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) -#include -#include -#define SET_INTERFACE -#endif - -#include "core.h" - -#include "utils.h" -#include "netutils.h" -#include "cache.h" -#include "udprelay.h" -#include "ss_ref.h" -#include "ss_windows.h" - -#ifdef MODULE_REMOTE -#define MAX_UDP_CONN_NUM 512 -#else -#define MAX_UDP_CONN_NUM 256 -#endif - -#ifdef MODULE_REMOTE -#ifdef MODULE_ -#error "MODULE_REMOTE and MODULE_LOCAL should not be both defined" -#endif -#endif - -#ifndef EAGAIN -#define EAGAIN EWOULDBLOCK -#endif - -#ifndef EWOULDBLOCK -#define EWOULDBLOCK EAGAIN -#endif - -static void server_recv_cb(SS_P_ ss_io *w, int revents); -static void remote_recv_cb(SS_P_ ss_io *w, int revents); -static void remote_timeout_cb(SS_P_ ss_timer *watcher, int revents); - -static char *hash_key(const int af, const struct sockaddr_storage *addr); -#ifdef MODULE_REMOTE -static void resolv_free_cb(void *data); -static void resolv_cb(struct sockaddr *addr, void *data); -#endif -static void close_and_free_remote(SS_P_ remote_ctx_t *ctx); -static remote_ctx_t *new_remote(int fd, server_ctx_t *server_ctx); - -#ifdef __ANDROID__ -extern uint64_t tx; -extern uint64_t rx; -extern int vpn; -extern void stat_update_cb(); -#endif - -extern int verbose; -extern int reuse_port; -#ifdef MODULE_REMOTE -extern uint64_t tx; -extern uint64_t rx; - -extern int is_bind_local_addr; -extern struct sockaddr_storage local_addr_v4; -extern struct sockaddr_storage local_addr_v6; -#endif - -static int packet_size = DEFAULT_PACKET_SIZE; -/* UDP preserves datagram boundaries. MTU is a transmission hint, not a - * receive limit: a smaller buffer silently truncates valid fragmented packets - * and makes authentication fail. Covers the full IPv4/IPv6 UDP datagram. */ -static const int buf_size = 65536; -static int server_num = 0; -static server_ctx_t *server_ctx_list[MAX_REMOTE_NUM] = { NULL }; - -const char *s_port = NULL; - -#ifndef __MINGW32__ -static int -setnonblocking(int fd) -{ - int flags; - if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { - flags = 0; - } - return fcntl(fd, F_SETFL, flags | O_NONBLOCK); -} - -#endif - -#if defined(MODULE_REMOTE) && defined(SO_BROADCAST) -static int -set_broadcast(int socket_fd) -{ - int opt = 1; - return ss_setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)); -} - -#endif - -#ifdef SO_NOSIGPIPE -static int -set_nosigpipe(int socket_fd) -{ - int opt = 1; - return ss_setsockopt(socket_fd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); -} - -#endif - -#ifdef MODULE_REDIR - -#ifndef IP_TRANSPARENT -#define IP_TRANSPARENT 19 -#endif - -#ifndef IPV6_TRANSPARENT -#define IPV6_TRANSPARENT 75 -#endif - -#ifndef IP_RECVORIGDSTADDR -#ifdef IP_ORIGDSTADDR -#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR -#else -#define IP_RECVORIGDSTADDR 20 -#endif -#endif - -#ifndef IPV6_RECVORIGDSTADDR -#ifdef IPV6_ORIGDSTADDR -#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR -#else -#define IPV6_RECVORIGDSTADDR 74 -#endif -#endif - -static int -get_dstaddr(struct msghdr *msg, struct sockaddr_storage *dstaddr) -{ - struct cmsghdr *cmsg; - - for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { - if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVORIGDSTADDR) { - memcpy(dstaddr, CMSG_DATA(cmsg), sizeof(struct sockaddr_in)); - dstaddr->ss_family = AF_INET; - return 0; - } else if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVORIGDSTADDR) { - memcpy(dstaddr, CMSG_DATA(cmsg), sizeof(struct sockaddr_in6)); - dstaddr->ss_family = AF_INET6; - return 0; - } - } - - return 1; -} - -#endif - -#define HASH_KEY_LEN sizeof(struct sockaddr_storage) + sizeof(int) -static char * -hash_key(const int af, const struct sockaddr_storage *addr) -{ - size_t addr_len = sizeof(struct sockaddr_storage); - static char key[HASH_KEY_LEN]; - - memset(key, 0, HASH_KEY_LEN); - memcpy(key, &af, sizeof(int)); - memcpy(key + sizeof(int), (const uint8_t *)addr, addr_len); - - return key; -} - -#if defined(MODULE_REDIR) || defined(MODULE_REMOTE) - -static int -construct_udprelay_header(const struct sockaddr_storage *in_addr, - char *addr_header) -{ - int addr_header_len = 0; - - if (in_addr->ss_family == AF_INET) { - struct sockaddr_in *addr = (struct sockaddr_in *)in_addr; - size_t addr_len = sizeof(struct in_addr); - - addr_header[addr_header_len++] = 1; - memcpy(addr_header + addr_header_len, &addr->sin_addr, addr_len); - addr_header_len += addr_len; - memcpy(addr_header + addr_header_len, &addr->sin_port, 2); - addr_header_len += 2; - } else if (in_addr->ss_family == AF_INET6) { - struct sockaddr_in6 *addr = (struct sockaddr_in6 *)in_addr; - size_t addr_len = sizeof(struct in6_addr); - - addr_header[addr_header_len++] = 4; - memcpy(addr_header + addr_header_len, &addr->sin6_addr, addr_len); - addr_header_len += addr_len; - memcpy(addr_header + addr_header_len, &addr->sin6_port, 2); - addr_header_len += 2; - } else { - return 0; - } - - return addr_header_len; -} - -#endif - -static int -parse_udprelay_header(const char *buf, const size_t buf_len, - char *host, char *port, struct sockaddr_storage *storage) -{ - if (buf_len < 1) { - return 0; - } - - const uint8_t atyp = *(uint8_t *)buf; - int offset = 1; - - // get remote addr and port - if ((atyp & ADDRTYPE_MASK) == 1) { - // IP V4 - size_t in_addr_len = sizeof(struct in_addr); - if (buf_len >= in_addr_len + 3) { - if (storage != NULL) { - struct sockaddr_in *addr = (struct sockaddr_in *)storage; - addr->sin_family = AF_INET; - memcpy(&addr->sin_addr, buf + offset, sizeof(struct in_addr)); - memcpy(&addr->sin_port, buf + offset + in_addr_len, sizeof(uint16_t)); - } - if (host != NULL) { - ss_inet_ntop(AF_INET, (const void *)(buf + offset), - host, INET_ADDRSTRLEN); - } - offset += in_addr_len; - } - } else if ((atyp & ADDRTYPE_MASK) == 3) { - // Domain name - if (buf_len < offset + 1) { - return 0; - } - uint8_t name_len = *(uint8_t *)(buf + offset); - if (name_len + 4 <= buf_len) { - if (storage != NULL) { - char tmp[MAX_HOSTNAME_LEN] = { 0 }; - struct ss_ip ip; - memcpy(tmp, buf + offset + 1, name_len); - tmp[name_len] = '\0'; - if (ss_ip_init(&ip, tmp) != -1) { - if (ip.version == 4) { - struct sockaddr_in *addr = (struct sockaddr_in *)storage; - inet_pton(AF_INET, tmp, &(addr->sin_addr)); - memcpy(&addr->sin_port, buf + offset + 1 + name_len, sizeof(uint16_t)); - addr->sin_family = AF_INET; - } else if (ip.version == 6) { - struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage; - inet_pton(AF_INET6, tmp, &(addr->sin6_addr)); - memcpy(&addr->sin6_port, buf + offset + 1 + name_len, sizeof(uint16_t)); - addr->sin6_family = AF_INET6; - } - } else if (!validate_hostname(tmp, name_len)) { - LOGE("[udp] invalid host name"); - return 0; - } - } - if (host != NULL) { - memcpy(host, buf + offset + 1, name_len); - host[name_len] = '\0'; - } - offset += 1 + name_len; - } - } else if ((atyp & ADDRTYPE_MASK) == 4) { - // IP V6 - size_t in6_addr_len = sizeof(struct in6_addr); - if (buf_len >= in6_addr_len + 3) { - if (storage != NULL) { - struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage; - addr->sin6_family = AF_INET6; - memcpy(&addr->sin6_addr, buf + offset, sizeof(struct in6_addr)); - memcpy(&addr->sin6_port, buf + offset + in6_addr_len, sizeof(uint16_t)); - } - if (host != NULL) { - ss_inet_ntop(AF_INET6, (const void *)(buf + offset), - host, INET6_ADDRSTRLEN); - } - offset += in6_addr_len; - } - } - - if (offset == 1) { - LOGE("[udp] invalid header with addr type %d", atyp); - return 0; - } - - if (port != NULL) { - snprintf(port, MAX_PORT_STR_LEN, "%d", load16_be(buf + offset)); - } - offset += 2; - - return offset; -} - -static char * -get_addr_str(const struct sockaddr *sa, bool has_port) -{ - static char s[SS_ADDRSTRLEN]; - memset(s, 0, SS_ADDRSTRLEN); - char addr[INET6_ADDRSTRLEN] = { 0 }; - char port[PORTSTRLEN] = { 0 }; - uint16_t p; - struct sockaddr_in sa_in; - struct sockaddr_in6 sa_in6; - - switch (sa->sa_family) { - case AF_INET: - memcpy(&sa_in, sa, sizeof(struct sockaddr_in)); - ss_inet_ntop(AF_INET, &sa_in.sin_addr, addr, INET_ADDRSTRLEN); - p = ntohs(sa_in.sin_port); - snprintf(port, sizeof(port), "%d", p); - break; - - case AF_INET6: - memcpy(&sa_in6, sa, sizeof(struct sockaddr_in6)); - ss_inet_ntop(AF_INET6, &sa_in6.sin6_addr, addr, INET6_ADDRSTRLEN); - p = ntohs(sa_in6.sin6_port); - snprintf(port, sizeof(port), "%d", p); - break; - - default: - strncpy(s, "Unknown AF", SS_ADDRSTRLEN); - } - - int addr_len = strlen(addr); - int port_len = strlen(port); - // s is a zeroed static buffer large enough for addr + ':' + port - memcpy(s, addr, addr_len); // NOLINT(bugprone-not-null-terminated-result) - - if (has_port) { - memcpy(s + addr_len + 1, port, port_len); // NOLINT(bugprone-not-null-terminated-result) - s[addr_len] = ':'; - } - - return s; -} - -int -create_remote_socket(int ipv6) -{ - int remote_sock; - - if (ipv6) { - // Try to bind IPv6 first - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(struct sockaddr_in6)); - addr.sin6_family = AF_INET6; - addr.sin6_addr = in6addr_any; - addr.sin6_port = 0; - remote_sock = ss_socket(AF_INET6, SOCK_DGRAM, 0); - if (remote_sock == -1) { - ERROR("[udp] cannot create socket"); - return -1; - } -#ifdef MODULE_REMOTE - if (is_bind_local_addr) { - if (local_addr_v6.ss_family == AF_INET6) { - if (bind_to_addr(&local_addr_v6, remote_sock) == -1) { - ERROR("bind_to_addr"); - FATAL("[udp] cannot bind socket"); - return -1; - } - } - } else { -#endif - if (bind(remote_sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { - FATAL("[udp] cannot bind socket"); - return -1; - } -#ifdef MODULE_REMOTE - } -#endif - } else { - // Or else bind to IPv4 - struct sockaddr_in addr; - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = 0; - remote_sock = ss_socket(AF_INET, SOCK_DGRAM, 0); - if (remote_sock == -1) { - ERROR("[udp] cannot create socket"); - return -1; - } -#ifdef MODULE_REMOTE - if (is_bind_local_addr) { - if (local_addr_v4.ss_family == AF_INET) { - if (bind_to_addr(&local_addr_v4, remote_sock) == -1) { - ERROR("bind_to_addr"); - FATAL("[udp] cannot bind socket"); - return -1; - } - } - } else { -#endif - if (bind(remote_sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { - FATAL("[udp] cannot bind remote"); - return -1; - } -#ifdef MODULE_REMOTE - } -#endif - } - -#if defined(__linux__) - // Disable fragmentation - int val = IP_PMTUDISC_DO; - ss_setsockopt(remote_sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); -#endif - - return remote_sock; -} - -int -create_server_socket(const char *host, const char *port) -{ - struct addrinfo hints; - struct addrinfo *result, *rp, *ipv4v6bindall; - int s, server_sock = -1; - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ - hints.ai_socktype = SOCK_DGRAM; /* We want a UDP socket */ - hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* For wildcard IP address */ - hints.ai_protocol = IPPROTO_UDP; - - s = getaddrinfo(host, port, &hints, &result); - if (s != 0) { - LOGE("[udp] getaddrinfo: %s", gai_strerror(s)); - return -1; - } - - if (result == NULL) { - LOGE("[udp] cannot bind"); - return -1; - } - - rp = result; - - /* - * On Linux, with net.ipv6.bindv6only = 0 (the default), getaddrinfo(NULL) with - * AI_PASSIVE returns 0.0.0.0 and :: (in this order). AI_PASSIVE was meant to - * return a list of addresses to listen on, but it is impossible to listen on - * 0.0.0.0 and :: at the same time, if :: implies dualstack mode. - */ - if (!host) { - ipv4v6bindall = result; - - /* Loop over all address infos found until a IPV6 address is found. */ - while (ipv4v6bindall) { - if (ipv4v6bindall->ai_family == AF_INET6) { - rp = ipv4v6bindall; /* Take first IPV6 address available */ - break; - } - ipv4v6bindall = ipv4v6bindall->ai_next; /* Get next address info, if any */ - } - } - - for (/*rp = result*/; rp != NULL; rp = rp->ai_next) { - server_sock = ss_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if (server_sock == -1) { - continue; - } - - if (rp->ai_family == AF_INET6) { - int ipv6only = host ? 1 : 0; - ss_setsockopt(server_sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)); - } - - int opt = 1; - ss_setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); -#ifdef SO_NOSIGPIPE - set_nosigpipe(server_sock); -#endif - if (reuse_port) { - int err = set_reuseport(server_sock); - if (err == 0) { - LOGI("udp port reuse enabled"); - } - } -#ifdef IP_TOS - // Set QoS flag - int tos = 46 << 2; - int rc = ss_setsockopt(server_sock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv4 dscp failed: %d", ss_socket_error()); - } -#ifdef IPV6_TCLASS - rc = ss_setsockopt(server_sock, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv6 dscp failed: %d", ss_socket_error()); - } -#endif -#endif - -#ifdef MODULE_REDIR - int sol = rp->ai_family == AF_INET ? SOL_IP : SOL_IPV6; - int flag_t = rp->ai_family == AF_INET ? IP_TRANSPARENT : IPV6_TRANSPARENT; - int flag_r = rp->ai_family == AF_INET ? IP_RECVORIGDSTADDR : IPV6_RECVORIGDSTADDR; - - if (ss_setsockopt(server_sock, sol, flag_t, &opt, sizeof(opt))) { - ERROR("[udp] setsockopt IP_TRANSPARENT"); - exit(EXIT_FAILURE); - } - - if (ss_setsockopt(server_sock, sol, flag_r, &opt, sizeof(opt))) { - FATAL("[udp] setsockopt IP_RECVORIGDSTADDR"); - } -#endif - - s = bind(server_sock, rp->ai_addr, rp->ai_addrlen); - if (s == 0) { - /* We managed to bind successfully! */ - break; - } else { - ERROR("[udp] bind"); - } - - ss_socket_close(server_sock); - server_sock = -1; - } - - freeaddrinfo(result); - -#if defined(__linux__) - // Disable fragmentation - int val = IP_PMTUDISC_DO; - ss_setsockopt(server_sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); -#endif - - return server_sock; -} - -remote_ctx_t * -new_remote(int fd, server_ctx_t *server_ctx) -{ - remote_ctx_t *ctx = (remote_ctx_t *)ss_malloc(sizeof(remote_ctx_t)); - memset(ctx, 0, sizeof(remote_ctx_t)); - - ctx->fd = fd; - ctx->server_ctx = server_ctx; - ctx->af = AF_UNSPEC; - - ss_io_init(&ctx->io, remote_recv_cb, fd, SS_READ); - ss_timer_init(&ctx->watcher, remote_timeout_cb, server_ctx->timeout, - server_ctx->timeout); - - return ctx; -} - -server_ctx_t * -new_server_ctx(int fd) -{ - server_ctx_t *ctx = (server_ctx_t *)ss_malloc(sizeof(server_ctx_t)); - memset(ctx, 0, sizeof(server_ctx_t)); - - ctx->fd = fd; - - ss_io_init(&ctx->io, server_recv_cb, fd, SS_READ); - - return ctx; -} - -#ifdef MODULE_REMOTE -struct query_ctx * -new_query_ctx(char *buf, size_t len) -{ - struct query_ctx *ctx = (struct query_ctx *)ss_malloc(sizeof(struct query_ctx)); - memset(ctx, 0, sizeof(struct query_ctx)); - ctx->buf = (buffer_t *)ss_malloc(sizeof(buffer_t)); - balloc(ctx->buf, len); - memcpy(ctx->buf->data, buf, len); - ctx->buf->len = len; - return ctx; -} - -void -close_and_free_query(SS_P_ struct query_ctx *ctx) -{ - if (ctx != NULL) { - if (ctx->buf != NULL) { - bfree(ctx->buf); - ss_free(ctx->buf); - } - ss_ptr_reset(&ctx->udp_session, ctx->server_ctx->crypto->udp_session_release); - ss_free(ctx); - } -} - -#endif - -void -close_and_free_remote(SS_P_ remote_ctx_t *ctx) -{ - if (ctx != NULL) { - ss_timer_stop(SS_A_ & ctx->watcher); - ss_io_stop(SS_A_ & ctx->io); - ss_socket_close(ctx->fd); - if (ctx->server_ctx != NULL) - ss_ptr_reset(&ctx->udp_session, ctx->server_ctx->crypto->udp_session_release); - ss_free(ctx); - } -} - -static void -remote_timeout_cb(SS_P_ ss_timer *watcher, int revents) -{ - remote_ctx_t *remote_ctx - = ss_container_of(watcher, remote_ctx_t, watcher); - - if (verbose) { - LOGI("[udp] connection timeout"); - } - - char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr); - cache_remove(remote_ctx->server_ctx->conn_cache, key, HASH_KEY_LEN); -} - -#ifdef MODULE_REMOTE -static void -resolv_free_cb(void *data) -{ - struct query_ctx *ctx = (struct query_ctx *)data; - if (ctx->buf != NULL) { - bfree(ctx->buf); - ss_free(ctx->buf); - } - ss_free(ctx); -} - -static void -resolv_cb(struct sockaddr *addr, void *data) -{ - struct query_ctx *query_ctx = (struct query_ctx *)data; - struct ss_loop *loop = query_ctx->server_ctx->loop; - - if (addr == NULL) { - LOGE("[udp] unable to resolve"); - } else { - remote_ctx_t *remote_ctx = query_ctx->remote_ctx; - int cache_hit = 0; - - // Lookup in the conn cache - if (remote_ctx == NULL) { - char *key = hash_key(AF_UNSPEC, &query_ctx->src_addr); - cache_lookup(query_ctx->server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx); - } - - if (remote_ctx == NULL) { - int remotefd = create_remote_socket(addr->sa_family == AF_INET6); - if (remotefd != -1) { - setnonblocking(remotefd); -#ifdef SO_BROADCAST - set_broadcast(remotefd); -#endif -#ifdef SO_NOSIGPIPE - set_nosigpipe(remotefd); -#endif -#ifdef IP_TOS - // Set QoS flag - int tos = 46 << 2; - int rc = ss_setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv4 dscp failed: %d", ss_socket_error()); - } -#ifdef IPV6_TCLASS - rc = ss_setsockopt(remotefd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv6 dscp failed: %d", ss_socket_error()); - } -#endif -#endif -#ifdef SET_INTERFACE - if (query_ctx->server_ctx->iface) { - if (setinterface(remotefd, query_ctx->server_ctx->iface) == -1) - ERROR("setinterface"); - } -#endif - remote_ctx = new_remote(remotefd, query_ctx->server_ctx); - remote_ctx->src_addr = query_ctx->src_addr; - remote_ctx->server_ctx = query_ctx->server_ctx; - } else { - ERROR("[udp] bind() error"); - } - } else { - cache_hit = 1; - } - - if (remote_ctx != NULL) { - ss_ptr_move(&remote_ctx->udp_session, &query_ctx->udp_session, - query_ctx->server_ctx->crypto->udp_session_release); - if (addr->sa_family == AF_INET) - memcpy(&remote_ctx->dst_addr, addr, sizeof(struct sockaddr_in)); - else - memcpy(&remote_ctx->dst_addr, addr, sizeof(struct sockaddr_in6)); - - size_t addr_len = get_sockaddr_len(addr); - int s = sendto(remote_ctx->fd, query_ctx->buf->data, query_ctx->buf->len, - 0, addr, addr_len); - - if (s == -1) { - ERROR("[udp] sendto_remote"); - if (!cache_hit) { - close_and_free_remote(SS_A_ remote_ctx); - } - } else { - if (!cache_hit) { - // Add to conn cache - char *key = hash_key(AF_UNSPEC, &remote_ctx->src_addr); - cache_insert(query_ctx->server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); - ss_io_start(SS_A_ & remote_ctx->io); - ss_timer_start(SS_A_ & remote_ctx->watcher); - } - } - } - } -} - -#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; - uint32_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(SS_P_ ss_io *w, int revents) -{ - ssize_t r; - remote_ctx_t *remote_ctx = (remote_ctx_t *)w; - server_ctx_t *server_ctx = remote_ctx->server_ctx; - - // server has been closed - if (server_ctx == NULL) { - LOGE("[udp] invalid server"); - close_and_free_remote(SS_A_ remote_ctx); - return; - } - - if (verbose) { - LOGI("[udp] remote receive a packet"); - } - - struct sockaddr_storage src_addr; - socklen_t src_addr_len = sizeof(struct sockaddr_storage); - memset(&src_addr, 0, src_addr_len); - - buffer_t *buf = (buffer_t *)ss_malloc(sizeof(buffer_t)); - balloc(buf, buf_size); - - // recv - r = recvfrom(remote_ctx->fd, buf->data, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len); - - if (r == -1) { - // error on recv - // simply drop that packet - ERROR("[udp] remote_recv_recvfrom"); - goto CLEAN_UP; - } else if (r > packet_size) { - if (verbose) { - LOGI("[udp] remote_recv_recvfrom fragmentation, MTU at least be: " SSIZE_FMT, r + PACKET_HEADER_SIZE); - } - } - - buf->len = r; - -#ifdef MODULE_LOCAL - int err; - err = server_ctx->crypto->decrypt_udp != NULL - ? server_ctx->crypto->decrypt_udp(buf, server_ctx->crypto->cipher, - buf_size, &remote_ctx->udp_session) - : server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size); - if (err) { - LOGE("failed to handshake with %s: %s", - get_addr_str((struct sockaddr *)&src_addr, false), "suspicious UDP packet"); - // drop the packet silently - goto CLEAN_UP; - } - -#ifdef MODULE_REDIR - struct sockaddr_storage dst_addr; - memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); - int len; - len = parse_udprelay_header(buf->data, buf->len, NULL, NULL, &dst_addr); - - if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) { - LOGI("[udp] ss-redir does not support domain name"); - goto CLEAN_UP; - } -#else - int len; - len = parse_udprelay_header(buf->data, buf->len, NULL, NULL, NULL); -#endif - - if (len == 0) { - // error when parsing header - LOGE("[udp] error in parse header"); - goto CLEAN_UP; - } - -#if defined(MODULE_TUNNEL) || defined(MODULE_REDIR) - // Construct packet - buf->len -= len; - memmove(buf->data, buf->data + len, buf->len); -#else -#ifdef __ANDROID__ - rx += buf->len; - stat_update_cb(); -#endif - // Construct packet - brealloc(buf, buf->len + 3, buf_size); - memmove(buf->data + 3, buf->data, buf->len); - memset(buf->data, 0, 3); - buf->len += 3; -#endif - -#endif - -#ifdef MODULE_REMOTE - - rx += buf->len; - - // Reconstruct UDP response header - char addr_header[MAX_ADDR_HEADER_SIZE]; - int addr_header_len; - addr_header_len = construct_udprelay_header(&src_addr, addr_header); - - // Construct packet - brealloc(buf, buf->len + addr_header_len, buf_size); - memmove(buf->data + addr_header_len, buf->data, buf->len); - memcpy(buf->data, addr_header, addr_header_len); - buf->len += addr_header_len; - - int err; - err = server_ctx->crypto->encrypt_udp != NULL - ? server_ctx->crypto->encrypt_udp(buf, server_ctx->crypto->cipher, - buf_size, &remote_ctx->udp_session) - : server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size); - if (err) { - // drop the packet silently - goto CLEAN_UP; - } - -#endif - - if (buf->len > packet_size) { - if (verbose) { - LOGI("[udp] remote_recv_sendto fragmentation, MTU at least be: " SIZE_FMT, buf->len + PACKET_HEADER_SIZE); - } - } - - -#ifdef MODULE_REDIR - convert_ipv4_mapped_ipv6(&dst_addr); - - size_t remote_dst_addr_len; - remote_dst_addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr); - - int src_fd; - src_fd = ss_socket(AF_INET6, SOCK_DGRAM, 0); - if (src_fd < 0) { - ERROR("[udp] remote_recv_socket"); - goto CLEAN_UP; - } - int opt; - opt = 1; - if (ss_setsockopt(src_fd, SOL_IPV6, IPV6_TRANSPARENT, &opt, sizeof(opt))) { - ERROR("[udp] remote_recv_setsockopt"); - ss_socket_close(src_fd); - goto CLEAN_UP; - } - if (ss_setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { - ERROR("[udp] remote_recv_setsockopt"); - ss_socket_close(src_fd); - goto CLEAN_UP; - } - if (reuse_port) { - if (set_reuseport(src_fd) != 0) { - ERROR("[udp] remote_recv port_reuse"); - } - } -#ifdef IP_TOS - // Set QoS flag - int tos; - tos = 46 << 2; - int rc; - rc = ss_setsockopt(src_fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv4 dscp failed: %d", ss_socket_error()); - } -#ifdef IPV6_TCLASS - rc = ss_setsockopt(src_fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv6 dscp failed: %d", ss_socket_error()); - } -#endif -#endif - if (bind(src_fd, (struct sockaddr *)&dst_addr, remote_dst_addr_len) != 0) { - ERROR("[udp] remote_recv_bind"); - ss_socket_close(src_fd); - 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; - remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&mapped_src_addr); - - int s; - s = sendto(src_fd, buf->data, buf->len, 0, - (struct sockaddr *)&mapped_src_addr, remote_src_addr_len); - if (s == -1 && !(ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK)) { - ERROR("[udp] remote_recv_sendto"); - ss_socket_close(src_fd); - goto CLEAN_UP; - } - ss_socket_close(src_fd); - -#else - size_t remote_src_addr_len; - remote_src_addr_len = get_sockaddr_len((struct sockaddr *)&remote_ctx->src_addr); - - int s; - s = sendto(server_ctx->fd, buf->data, buf->len, 0, - (struct sockaddr *)&remote_ctx->src_addr, remote_src_addr_len); - if (s == -1 && !(ss_socket_error() == EAGAIN || ss_socket_error() == EWOULDBLOCK)) { - ERROR("[udp] remote_recv_sendto"); - goto CLEAN_UP; - } - -#endif - - // handle the UDP packet successfully, - // triger the timer - ss_timer_again(SS_A_ & remote_ctx->watcher); - -CLEAN_UP: - - bfree(buf); - ss_free(buf); -} - -static void -server_recv_cb(SS_P_ ss_io *w, int revents) -{ - server_ctx_t *server_ctx = (server_ctx_t *)w; - struct sockaddr_storage src_addr; - memset(&src_addr, 0, sizeof(struct sockaddr_storage)); - - buffer_t *buf = (buffer_t *)ss_malloc(sizeof(buffer_t)); - balloc(buf, buf_size); - - socklen_t src_addr_len = sizeof(struct sockaddr_storage); - unsigned int offset = 0; -#ifdef MODULE_REMOTE - void *udp_session = NULL; -#endif - -#ifdef MODULE_REDIR - char control_buffer[64] = { 0 }; - struct msghdr msg; - memset(&msg, 0, sizeof(struct msghdr)); - struct iovec iov[1]; - struct sockaddr_storage dst_addr; - memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); - - msg.msg_name = &src_addr; - msg.msg_namelen = src_addr_len; - msg.msg_control = control_buffer; - msg.msg_controllen = sizeof(control_buffer); - - iov[0].iov_base = buf->data; - iov[0].iov_len = buf_size; - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - buf->len = recvmsg(server_ctx->fd, &msg, 0); - if (buf->len == -1) { - ERROR("[udp] server_recvmsg"); - goto CLEAN_UP; - } else if (buf->len > packet_size) { - if (verbose) { - LOGI("[udp] UDP server_recv_recvmsg fragmentation, MTU at least be: " SIZE_FMT, - buf->len + PACKET_HEADER_SIZE); - } - } - - if (get_dstaddr(&msg, &dst_addr)) { - LOGE("[udp] unable to get dest addr"); - goto CLEAN_UP; - } -#else - ssize_t r; - r = recvfrom(server_ctx->fd, buf->data, buf_size, - 0, (struct sockaddr *)&src_addr, &src_addr_len); - - if (r == -1) { - // error on recv - // simply drop that packet - ERROR("[udp] server_recv_recvfrom"); - goto CLEAN_UP; - } else if (r > packet_size) { - if (verbose) { - LOGI("[udp] server_recv_recvfrom fragmentation, MTU at least be: " SSIZE_FMT, r + PACKET_HEADER_SIZE); - } - } - - buf->len = r; -#endif - - if (verbose) { - LOGI("[udp] server receive a packet"); - } - -#ifdef MODULE_REMOTE - tx += buf->len; - - /* - * AEAD-2022 routes by client session ID, which is only known after - * decryption, so the crypto layer resolves the session itself and hands - * it back here to be attached to the relay context. - */ - int err; - err = server_ctx->crypto->decrypt_udp != NULL - ? server_ctx->crypto->decrypt_udp(buf, server_ctx->crypto->cipher, - buf_size, &udp_session) - : server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size); - if (err) { - LOGE("failed to handshake with %s: %s", - get_addr_str((struct sockaddr *)&src_addr, false), "suspicious UDP packet"); - // drop the packet silently - goto CLEAN_UP; - } -#endif - -#ifdef MODULE_LOCAL -#if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR) -#ifdef __ANDROID__ - tx += buf->len; -#endif - if (buf->len < 3) { - LOGE("[udp] invalid SOCKS5 UDP header"); - goto CLEAN_UP; - } - uint8_t frag; - frag = *(uint8_t *)(buf->data + 2); - offset += 3; -#endif -#endif - - /* - * - * SOCKS5 UDP Request - * +----+------+------+----------+----------+----------+ - * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | - * +----+------+------+----------+----------+----------+ - * | 2 | 1 | 1 | Variable | 2 | Variable | - * +----+------+------+----------+----------+----------+ - * - * SOCKS5 UDP Response - * +----+------+------+----------+----------+----------+ - * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | - * +----+------+------+----------+----------+----------+ - * | 2 | 1 | 1 | Variable | 2 | Variable | - * +----+------+------+----------+----------+----------+ - * - * shadowsocks UDP Request (before encrypted) - * +------+----------+----------+----------+ - * | ATYP | DST.ADDR | DST.PORT | DATA | - * +------+----------+----------+----------+ - * | 1 | Variable | 2 | Variable | - * +------+----------+----------+----------+ - * - * shadowsocks UDP Response (before encrypted) - * +------+----------+----------+----------+ - * | ATYP | DST.ADDR | DST.PORT | DATA | - * +------+----------+----------+----------+ - * | 1 | Variable | 2 | Variable | - * +------+----------+----------+----------+ - * - * shadowsocks UDP Request and Response (after encrypted) - * +-------+--------------+ - * | IV | PAYLOAD | - * +-------+--------------+ - * | Fixed | Variable | - * +-------+--------------+ - * - */ - -#ifdef MODULE_REDIR - char addr_header[MAX_ADDR_HEADER_SIZE]; - memset(addr_header, 0, sizeof(addr_header)); - int addr_header_len; - addr_header_len = construct_udprelay_header(&dst_addr, addr_header); - - if (addr_header_len == 0) { - LOGE("[udp] failed to parse tproxy addr"); - goto CLEAN_UP; - } - - // reconstruct the buffer - brealloc(buf, buf->len + addr_header_len, buf_size); - memmove(buf->data + addr_header_len, buf->data, buf->len); - memcpy(buf->data, addr_header, addr_header_len); - buf->len += addr_header_len; - -#elif MODULE_TUNNEL - - char addr_header[MAX_ADDR_HEADER_SIZE]; - memset(addr_header, 0, sizeof(addr_header)); - char *host; - host = server_ctx->tunnel_addr.host; - char *port; - port = server_ctx->tunnel_addr.port; - uint16_t port_num; - port_num = 0; - if (ss_parse_uint16_port(port, &port_num) == -1) { - LOGE("[udp] invalid tunnel port"); - goto CLEAN_UP; - } - uint16_t port_net_num; - port_net_num = htons(port_num); - int addr_header_len; - addr_header_len = 0; - - struct ss_ip ip; - if (ss_ip_init(&ip, host) != -1) { - if (ip.version == 4) { - // send as IPv4 - struct in_addr host_addr; - memset(&host_addr, 0, sizeof(struct in_addr)); - int host_len = sizeof(struct in_addr); - - if (inet_pton(AF_INET, host, &host_addr) == -1) { - FATAL("IP parser error"); - } - addr_header[addr_header_len++] = 1; - memcpy(addr_header + addr_header_len, &host_addr, host_len); - addr_header_len += host_len; - } else if (ip.version == 6) { - // send as IPv6 - struct in6_addr host_addr; - memset(&host_addr, 0, sizeof(struct in6_addr)); - int host_len = sizeof(struct in6_addr); - - if (inet_pton(AF_INET6, host, &host_addr) == -1) { - FATAL("IP parser error"); - } - addr_header[addr_header_len++] = 4; - memcpy(addr_header + addr_header_len, &host_addr, host_len); - addr_header_len += host_len; - } else { - FATAL("IP parser error"); - } - } else { - // send as domain - int host_len = strlen(host); - - if (host_len > UINT8_MAX) { - LOGE("[udp] tunnel host name is too long"); - goto CLEAN_UP; - } - addr_header[addr_header_len++] = 3; - addr_header[addr_header_len++] = host_len; - // addr_header is a binary protocol buffer, not a C string - memcpy(addr_header + addr_header_len, host, host_len); // NOLINT(bugprone-not-null-terminated-result) - addr_header_len += host_len; - } - memcpy(addr_header + addr_header_len, &port_net_num, 2); - addr_header_len += 2; - - // reconstruct the buffer - brealloc(buf, buf->len + addr_header_len, buf_size); - memmove(buf->data + addr_header_len, buf->data, buf->len); - memcpy(buf->data, addr_header, addr_header_len); - buf->len += addr_header_len; - -#else - - char host[MAX_HOSTNAME_LEN]; - char port[MAX_PORT_STR_LEN]; - memset(host, 0, sizeof(host)); - memset(port, 0, sizeof(port)); - struct sockaddr_storage dst_addr; - memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); - - int addr_header_len; - addr_header_len = parse_udprelay_header(buf->data + offset, buf->len - offset, - host, port, &dst_addr); - if (addr_header_len == 0) { - // error in parse header - goto CLEAN_UP; - } - -#endif - - char *key; -#ifdef MODULE_LOCAL - key = hash_key(server_ctx->remote_addr->sa_family, &src_addr); -#else - key = hash_key(dst_addr.ss_family, &src_addr); -#endif - - struct cache *conn_cache; - conn_cache = server_ctx->conn_cache; - - remote_ctx_t *remote_ctx; - remote_ctx = NULL; - cache_lookup(conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx); - - if (remote_ctx != NULL) { - if (sockaddr_cmp(&src_addr, &remote_ctx->src_addr, sizeof(src_addr))) { - remote_ctx = NULL; - } - } - - // reset the timer - if (remote_ctx != NULL) { - ss_timer_again(SS_A_ & remote_ctx->watcher); - } - - if (remote_ctx == NULL) { - if (verbose) { -#ifdef MODULE_REDIR - char src[SS_ADDRSTRLEN]; - char dst[SS_ADDRSTRLEN]; - strcpy(src, get_addr_str((struct sockaddr *)&src_addr, true)); - strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr, true)); - LOGI("[%s] [udp] cache miss: %s <-> %s", s_port, dst, src); -#else - LOGI("[%s] [udp] cache miss: %s:%s <-> %s", s_port, host, port, - get_addr_str((struct sockaddr *)&src_addr, true)); -#endif - } - } else { - if (verbose) { -#ifdef MODULE_REDIR - char src[SS_ADDRSTRLEN]; - char dst[SS_ADDRSTRLEN]; - strcpy(src, get_addr_str((struct sockaddr *)&src_addr, true)); - strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr, true)); - LOGI("[%s] [udp] cache hit: %s <-> %s", s_port, dst, src); -#else - LOGI("[%s] [udp] cache hit: %s:%s <-> %s", s_port, host, port, - get_addr_str((struct sockaddr *)&src_addr, true)); -#endif - } - } - -#ifdef MODULE_LOCAL - -#if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR) - if (frag) { - LOGE("[udp] drop a message since frag is not 0, but %d", frag); - goto CLEAN_UP; - } -#endif - - const struct sockaddr *remote_addr; - int remote_addr_len; - remote_addr = server_ctx->remote_addr; - remote_addr_len = server_ctx->remote_addr_len; - - if (remote_ctx == NULL) { - // Bind to any port - int remotefd = create_remote_socket(remote_addr->sa_family == AF_INET6); - if (remotefd < 0) { - ERROR("[udp] udprelay bind() error"); - goto CLEAN_UP; - } - setnonblocking(remotefd); - -#ifdef SO_NOSIGPIPE - set_nosigpipe(remotefd); -#endif -#ifdef IP_TOS - // Set QoS flag - int tos = 46 << 2; - int rc = ss_setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv4 dscp failed: %d", ss_socket_error()); - } -#ifdef IPV6_TCLASS - rc = ss_setsockopt(remotefd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv6 dscp failed: %d", ss_socket_error()); - } -#endif -#endif -#ifdef SET_INTERFACE - if (server_ctx->iface) { - if (setinterface(remotefd, server_ctx->iface) == -1) - ERROR("setinterface"); - } -#endif - -#ifdef __ANDROID__ - if (vpn) { - if (protect_socket(remotefd) == -1) { - ERROR("protect_socket"); - ss_socket_close(remotefd); - goto CLEAN_UP; - } - } -#endif - - // Init remote_ctx - remote_ctx = new_remote(remotefd, server_ctx); - remote_ctx->src_addr = src_addr; - remote_ctx->af = remote_addr->sa_family; - - // Add to conn cache - cache_insert(conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); - - // Start remote io - ss_io_start(SS_A_ & remote_ctx->io); - ss_timer_start(SS_A_ & remote_ctx->watcher); - } - - if (offset > 0) { - buf->len -= offset; - memmove(buf->data, buf->data + offset, buf->len); - } - - int err; - err = server_ctx->crypto->encrypt_udp != NULL - ? server_ctx->crypto->encrypt_udp(buf, server_ctx->crypto->cipher, - buf_size, &remote_ctx->udp_session) - : server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size); - - if (err) { - // drop the packet silently - goto CLEAN_UP; - } - - if (buf->len > packet_size) { - if (verbose) { - LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SIZE_FMT, buf->len + PACKET_HEADER_SIZE); - } - } - - int s; - s = sendto(remote_ctx->fd, buf->data, buf->len, 0, remote_addr, remote_addr_len); - - if (s == -1) { - ERROR("[udp] server_recv_sendto"); - } - -#else - - int cache_hit; - cache_hit = 0; - int need_query; - need_query = 0; - - char *addr_header; - addr_header = buf->data + offset; - - if (buf->len - addr_header_len > packet_size) { - if (verbose) { - LOGI("[udp] server_recv_sendto fragmentation, MTU at least be: " SIZE_FMT, - buf->len - addr_header_len + PACKET_HEADER_SIZE); - } - } - - if (remote_ctx != NULL) { - cache_hit = 1; - if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) { - need_query = 1; - } - } else { - if (dst_addr.ss_family == AF_INET || dst_addr.ss_family == AF_INET6) { - int remotefd = create_remote_socket(dst_addr.ss_family == AF_INET6); - if (remotefd != -1) { - setnonblocking(remotefd); -#ifdef SO_BROADCAST - set_broadcast(remotefd); -#endif -#ifdef SO_NOSIGPIPE - set_nosigpipe(remotefd); -#endif -#ifdef IP_TOS - // Set QoS flag - int tos = 46 << 2; - int rc = ss_setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv4 dscp failed: %d", ss_socket_error()); - } -#ifdef IPV6_TCLASS - rc = ss_setsockopt(remotefd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); - if (rc < 0 && ss_socket_error() != ENOPROTOOPT) { - LOGE("setting ipv6 dscp failed: %d", ss_socket_error()); - } -#endif -#endif -#ifdef SET_INTERFACE - if (server_ctx->iface) { - if (setinterface(remotefd, server_ctx->iface) == -1) - ERROR("setinterface"); - } -#endif - remote_ctx = new_remote(remotefd, server_ctx); - remote_ctx->src_addr = src_addr; - remote_ctx->server_ctx = server_ctx; - memcpy(&remote_ctx->dst_addr, &dst_addr, sizeof(struct sockaddr_storage)); - } else { - ERROR("[udp] bind() error"); - goto CLEAN_UP; - } - } - } - - if (remote_ctx != NULL && !need_query) { - ss_ptr_move(&remote_ctx->udp_session, &udp_session, - server_ctx->crypto->udp_session_release); - } - - if (remote_ctx != NULL && !need_query) { - size_t addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr); - int s = sendto(remote_ctx->fd, buf->data + addr_header_len, - buf->len - addr_header_len, 0, - (struct sockaddr *)&dst_addr, addr_len); - - if (s == -1) { - ERROR("[udp] sendto_remote"); - if (!cache_hit) { - close_and_free_remote(SS_A_ remote_ctx); - } - } else { - if (!cache_hit) { - // Add to conn cache - remote_ctx->af = dst_addr.ss_family; - char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr); - cache_insert(server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); - - ss_io_start(SS_A_ & remote_ctx->io); - ss_timer_start(SS_A_ & remote_ctx->watcher); - } - } - } else { - struct query_ctx *query_ctx = new_query_ctx(buf->data + addr_header_len, - buf->len - addr_header_len); - query_ctx->server_ctx = server_ctx; - ss_ptr_move(&query_ctx->udp_session, &udp_session, - server_ctx->crypto->udp_session_release); - query_ctx->addr_header_len = addr_header_len; - query_ctx->src_addr = src_addr; - memcpy(query_ctx->addr_header, addr_header, addr_header_len); - - if (need_query) { - query_ctx->remote_ctx = remote_ctx; - } - - int port_num = 0; - if (ss_parse_int(port, 0, UINT16_MAX, &port_num) == -1) { - LOGE("[udp] invalid target port"); - resolv_free_cb(query_ctx); - goto CLEAN_UP; - } - resolv_start(host, htons((uint16_t)port_num), resolv_cb, resolv_free_cb, query_ctx); - } -#endif - -CLEAN_UP: -#ifdef MODULE_REMOTE - ss_ptr_reset(&udp_session, server_ctx->crypto->udp_session_release); -#endif - bfree(buf); - ss_free(buf); -} - -void -free_cb(void *key, void *element) -{ - remote_ctx_t *remote_ctx = (remote_ctx_t *)element; - - if (verbose) { - LOGI("[udp] one connection freed"); - } - - close_and_free_remote(SS_DEFAULT, remote_ctx); -} - -int -init_udprelay(const char *server_host, const char *server_port, -#ifdef MODULE_LOCAL - const struct sockaddr *remote_addr, const int remote_addr_len, -#ifdef MODULE_TUNNEL - const ss_addr_t tunnel_addr, -#endif -#endif - int mtu, crypto_t *crypto, int timeout, const char *iface) -{ - s_port = server_port; - // Initialize ev loop - struct ss_loop *loop = SS_DEFAULT; - - // Initialize MTU - if (mtu > 0) { - if (mtu <= PACKET_HEADER_SIZE) { - LOGE("MTU must be greater than %d", PACKET_HEADER_SIZE); - return -1; - } - packet_size = mtu - PACKET_HEADER_SIZE; - } - - // //////////////////////////////////////////////// - // Setup server context - - // Bind to port - int serverfd = create_server_socket(server_host, server_port); - if (serverfd < 0) { - return -1; - } - setnonblocking(serverfd); - - // Initialize cache - struct cache *conn_cache; - cache_create(&conn_cache, MAX_UDP_CONN_NUM, free_cb); - - server_ctx_t *server_ctx = new_server_ctx(serverfd); -#ifdef MODULE_REMOTE - server_ctx->loop = loop; -#endif - server_ctx->timeout = max(timeout, MIN_UDP_TIMEOUT); - server_ctx->crypto = crypto; - server_ctx->iface = iface; - server_ctx->conn_cache = conn_cache; -#ifdef MODULE_LOCAL - server_ctx->remote_addr = remote_addr; - server_ctx->remote_addr_len = remote_addr_len; -#ifdef MODULE_TUNNEL - server_ctx->tunnel_addr = tunnel_addr; -#endif -#endif - - ss_io_start(loop, &server_ctx->io); - - server_ctx_list[server_num++] = server_ctx; - - return serverfd; -} - -void -free_udprelay() -{ - struct ss_loop *loop = SS_DEFAULT; - while (server_num > 0) { - server_ctx_t *server_ctx = server_ctx_list[--server_num]; - ss_io_stop(loop, &server_ctx->io); - ss_socket_close(server_ctx->fd); - cache_delete(server_ctx->conn_cache, 0); -#ifdef MODULE_LOCAL - free((char*) server_ctx->remote_addr); -#endif - ss_free(server_ctx); - server_ctx_list[server_num] = NULL; - } -} diff --git a/src/udprelay.h b/src/udprelay.h deleted file mode 100644 index dcb28880..00000000 --- a/src/udprelay.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * udprelay.h - Define UDP relay's buffers and callbacks - * - * Copyright (C) 2013 - 2019, Max Lv - * - * This file is part of the shadowsocks-libev. - * - * shadowsocks-libev is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * shadowsocks-libev is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with shadowsocks-libev; see the file COPYING. If not, see - * . - */ - -#ifndef _UDPRELAY_H -#define _UDPRELAY_H - -#include - -#include "ss_event.h" - -#include "crypto.h" -#include "jconf.h" - -#ifdef MODULE_REMOTE -#include "resolv.h" -#endif - -#include "cache.h" - -#include "common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_UDP_PACKET_SIZE (65507) - -#define PACKET_HEADER_SIZE (1 + 28 + 2 + 64) -#define DEFAULT_PACKET_SIZE 1397 // 1492 - PACKET_HEADER_SIZE = 1397, the default MTU for UDP relay -#define MAX_ADDR_HEADER_SIZE (1 + 256 + 2) // 1-byte atyp + 256-byte hostname + 2-byte port - -typedef struct server_ctx { - ss_io io; - int fd; - crypto_t *crypto; - int timeout; - const char *iface; - struct cache *conn_cache; -#ifdef MODULE_LOCAL - const struct sockaddr *remote_addr; - int remote_addr_len; -#ifdef MODULE_TUNNEL - ss_addr_t tunnel_addr; -#endif -#endif -#ifdef MODULE_REMOTE - struct ss_loop *loop; -#endif -} server_ctx_t; - -#ifdef MODULE_REMOTE -typedef struct query_ctx { - struct sockaddr_storage src_addr; - buffer_t *buf; - int addr_header_len; - char addr_header[MAX_ADDR_HEADER_SIZE]; - struct server_ctx *server_ctx; - struct remote_ctx *remote_ctx; - void *udp_session; /* Owned until transferred to the resolved relay. */ -} query_ctx_t; -#endif - -typedef struct remote_ctx { - ss_io io; - ss_timer watcher; - int af; - int fd; - struct sockaddr_storage src_addr; -#ifdef MODULE_REMOTE - struct sockaddr_storage dst_addr; -#endif - /* - * AEAD-2022 UDP session state for this conversation, owned by the - * crypto layer and released with crypto->udp_session_release. - * NULL for legacy ciphers. - */ - void *udp_session; - struct server_ctx *server_ctx; -} remote_ctx_t; - -#ifdef __cplusplus -} -#endif - -#endif // _UDPRELAY_H