From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server-vie001.gnuweeb.org X-Spam-Level: X-Spam-Status: No, score=-1.2 required=5.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,URIBL_ZEN_BLOCKED_OPENDNS autolearn=ham autolearn_force=no version=3.4.6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gnuweeb.org; s=new2025; t=1756438675; bh=68afwpqG17KPeoIJTZDZTKxcVGNOZ1HVX1oRBWenIQg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding:Message-ID:Date:From: Reply-To:Subject:To:Cc:In-Reply-To:References:Resent-Date: Resent-From:Resent-To:Resent-Cc:User-Agent:Content-Type: Content-Transfer-Encoding; b=AJJmWX0c3PFntx0z31Um4kZWqbG4LWHFPZdtpfShywYiYtEA36qRCYKPqJJYYJfGv 9r/tl4j7pmk7CNNagR2TL//tzpJAehpdG4y2QgO2Ct1V2WqwVMj2xwTiII/YA8BPuw D1zwoRsDT/JqGhS/N/kBCTZeAw2rbgwNggHXj3wgzGUzLWIriltVr0vZTpWj5b3KT2 Q6J5T9w9X3aRwbXKEhxp/tvGia6545uuytXz40aNwxHxKBC64Ev6M9uyHdz4Okjfo2 EfH3azgukz7QD3N6zlb53wpLbUnTtryhVuWlorRVFsj8xnh33ES4X0YGXDDkjbfsbK UuRyqe2Rqfu8g== Received: from zero (unknown [182.253.228.107]) by server-vie001.gnuweeb.org (Postfix) with ESMTPSA id 3FB283127E97; Fri, 29 Aug 2025 03:37:54 +0000 (UTC) From: Ahmad Gani To: Ammar Faizi Cc: Ahmad Gani , Alviro Iskandar Setiawan , GNU/Weeb Mailing List Subject: [PATCH gwproxy v7 2/2] gwproxy: refactor code base to add experimental raw DNS backend Date: Fri, 29 Aug 2025 10:36:25 +0700 Message-ID: <20250829033628.573589-3-reyuki@gnuweeb.org> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250829033628.573589-1-reyuki@gnuweeb.org> References: <20250829033628.573589-1-reyuki@gnuweeb.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: The raw DNS backend is now marked as experimental and disabled by default. It can be enabled at build time with the configure option --use-raw-dns, and at runtime with the gwproxy option -r 1. Add fallback mechanism for raw DNS If *_PREFER_* is used in the restyp, the raw DNS backend will attempt to retry DNS query with different address family. Add DNS server option (remove hard-coded DNS server) Introduce --dns-server gwproxy' cmdline option instead of hard-coded value. Signed-off-by: Ahmad Gani --- Makefile | 2 +- configure | 8 ++ src/gwproxy/dns.c | 240 ++++++++++++++++++++++++++++++++++++----- src/gwproxy/dns.h | 29 ++++- src/gwproxy/ev/epoll.c | 69 ++++++++++-- src/gwproxy/gwproxy.c | 54 ++++++++-- src/gwproxy/gwproxy.h | 5 +- 7 files changed, 358 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 3ac35f052793..eb750e0fc31c 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ LIBGWPSOCKS5_TEST_CC_SOURCES = $(GWPROXY_DIR)/tests/socks5.c LIBGWPSOCKS5_TEST_OBJECTS = $(LIBGWPSOCKS5_TEST_CC_SOURCES:%.c=%.c.o) LIBGWDNS_TARGET = libgwdns.so -LIBGWDNS_CC_SOURCES = $(GWPROXY_DIR)/dns.c $(GWPROXY_DIR)/dns_cache.c +LIBGWDNS_CC_SOURCES = $(GWPROXY_DIR)/dns.c $(GWPROXY_DIR)/dnsparser.c $(GWPROXY_DIR)/dns_cache.c $(GWPROXY_DIR)/net.c LIBGWDNS_OBJECTS = $(LIBGWDNS_CC_SOURCES:%.c=%.c.o) LIBGWDNS_TEST_TARGET = $(GWPROXY_DIR)/tests/dns.t LIBGWDNS_TEST_CC_SOURCES = $(GWPROXY_DIR)/tests/dns.c diff --git a/configure b/configure index cef07b1cb652..539610916149 100755 --- a/configure +++ b/configure @@ -34,6 +34,9 @@ for opt do --cxx=*) cxx="$optarg"; ;; + --use-raw-dns) + use_raw_dns="yes"; + ;; --use-io-uring) use_io_uring="yes"; ;; @@ -87,6 +90,7 @@ Options: [defaults in brackets after descriptions] --cxx=CMD Use CMD as the C++ compiler --debug Build with debug enabled --use-io-uring Enable io_uring support (default: no) + --use-raw-dns Enable experimental raw DNS backend (default: no) --sanitize Enable sanitizers (default: no) EOF exit 0; @@ -333,6 +337,10 @@ if test "${use_io_uring}" = "yes"; then CXXFLAGS="${CXXFLAGS} -I./src/liburing/src/include"; fi; +if test "${use_raw_dns}" = "yes"; then + add_config "CONFIG_RAW_DNS"; +fi; + if test "${use_sanitize}" = "yes"; then add_config "CONFIG_SANITIZE"; if ! add_c_and_cxx_flag "-fsanitize=address"; then diff --git a/src/gwproxy/dns.c b/src/gwproxy/dns.c index cdc62a5bcf78..9f563e083fd2 100644 --- a/src/gwproxy/dns.c +++ b/src/gwproxy/dns.c @@ -23,6 +23,7 @@ #include #include +#include struct gwp_dns_ctx; @@ -33,6 +34,14 @@ struct gwp_dns_wrk { }; struct gwp_dns_ctx { +#ifdef CONFIG_RAW_DNS + uint32_t entry_cap; + struct gwp_dns_entry **entries; + int sockfd; + int ns_family; + struct gwp_sockaddr ns_addr; + uint8_t ns_addrlen; +#endif volatile bool should_stop; pthread_mutex_t lock; pthread_cond_t cond; @@ -182,6 +191,116 @@ int gwp_dns_resolve(struct gwp_dns_ctx *ctx, const char *name, return found ? 0 : -EHOSTUNREACH; } +#ifdef CONFIG_RAW_DNS + +void cp_nsaddr(struct gwp_dns_ctx *ctx, struct gwp_sockaddr *addr, uint8_t *addrlen) +{ + *addr = ctx->ns_addr; + *addrlen = ctx->ns_addrlen; +} + +static void _gwp_dns_entry_free(struct gwp_dns_entry *e) +{ + assert(e); + assert(e->udp_fd >= 0); + close(e->udp_fd); + free(e->name); + free(e); +} + +void gwp_dns_raw_entry_free(struct gwp_dns_ctx *ctx, struct gwp_dns_entry *e) +{ + struct gwp_dns_entry *new_e; + + assert(e); + + new_e = ctx->entries[--ctx->nr_entries]; + assert(ctx->nr_entries == new_e->idx); + new_e->idx = e->idx; + ctx->entries[e->idx] = new_e; + ctx->entries[ctx->nr_entries] = NULL; + + _gwp_dns_entry_free(e); +} + +static void free_all_queued_entries(struct gwp_dns_ctx *ctx) +{ + uint32_t i; + for (i = 0; i < ctx->nr_entries; i++) { + struct gwp_dns_entry *e = ctx->entries[i]; + _gwp_dns_entry_free(e); + } + + free(ctx->entries); +} + +static bool realloc_entries(struct gwp_dns_ctx *ctx) +{ + struct gwp_dns_entry **tmp; + int new_cap; + + new_cap = ctx->entry_cap * 2; + tmp = realloc(ctx->entries, new_cap * sizeof(*tmp)); + if (!tmp) + return 1; + + ctx->entries = tmp; + ctx->entry_cap = new_cap; + + return 0; +} + +int gwp_dns_process(struct gwp_dns_ctx *ctx, struct gwp_dns_entry *e) +{ + struct gwdns_addrinfo_node *ai; + uint8_t buff[UDP_MSG_LIMIT]; + ssize_t r; + + r = __sys_recvfrom( + e->udp_fd, buff, sizeof(buff), 0, + &ctx->ns_addr.sa, (socklen_t *)&ctx->ns_addrlen + ); + if (r <= 0) + return (int)r; + + r = gwdns_parse_query(e->txid, e->service, buff, r, &ai); + if (r) { + if (r == -ENODATA) { + uint16_t txid; + int af; + + /* Fallback to other family if this one yield no results */ + switch (ctx->cfg.restyp) { + case GWP_DNS_RESTYP_PREFER_IPV4: + af = AF_INET6; + break; + case GWP_DNS_RESTYP_PREFER_IPV6: + af = AF_INET; + break; + default: + goto exit_free_ai; + break; + } + + txid = (uint16_t)rand(); + r = gwdns_build_query(txid, e->name, af, e->payload, sizeof(e->payload)); + if (r > 0) { + e->txid = txid; + e->payloadlen = (int)r; + r = -EAGAIN; + } + } + goto exit_free_ai; + } + + e->addr = ai->ai_addr; + +exit_free_ai: + gwdns_free_parsed_query(ai); + return (int)r; +} +#endif /* #ifndef CONFIG_RAW_DNS */ + static void gwp_dns_entry_free(struct gwp_dns_entry *e) { if (!e) @@ -719,33 +838,48 @@ int gwp_dns_ctx_init(struct gwp_dns_ctx **ctx_p, const struct gwp_dns_cfg *cfg) goto out_free_ctx; } - r = pthread_cond_init(&ctx->cond, NULL); - if (r) { - r = -r; + if (cfg->use_raw_dns) { +#ifdef CONFIG_RAW_DNS + r = convert_str_to_ssaddr(cfg->ns_addr_str, &ctx->ns_addr, 53); + if (r) goto out_destroy_mutex; + ctx->ns_addrlen = ctx->ns_addr.sa.sa_family == AF_INET + ? sizeof(ctx->ns_addr.i4) + : sizeof(ctx->ns_addr.i6); + ctx->entry_cap = DEFAULT_ENTRIES_CAP; + ctx->entries = malloc(ctx->entry_cap * sizeof(*ctx->entries)); + if (!ctx->entries) + goto out_destroy_mutex; +#endif + } else { + r = pthread_cond_init(&ctx->cond, NULL); + if (r) { + r = -r; + goto out_destroy_mutex; + } + + ctx->nr_sleeping = 0; + ctx->workers = NULL; + ctx->head = NULL; + ctx->tail = NULL; + r = init_workers(ctx); + if (r) + goto out_destroy_cond; } + ctx->nr_entries = 0; r = init_cache(ctx); if (r) goto out_destroy_cond; - ctx->nr_sleeping = 0; - ctx->nr_entries = 0; - ctx->workers = NULL; - ctx->head = NULL; - ctx->tail = NULL; ctx->should_stop = false; ctx->last_scan = time(NULL); - r = init_workers(ctx); - if (r) - goto out_free_cache; *ctx_p = ctx; return 0; -out_free_cache: - free_cache(ctx->cache); out_destroy_cond: - pthread_cond_destroy(&ctx->cond); + if (!cfg->use_raw_dns) + pthread_cond_destroy(&ctx->cond); out_destroy_mutex: pthread_mutex_destroy(&ctx->lock); out_free_ctx: @@ -762,10 +896,16 @@ static void put_all_queued_entries(struct gwp_dns_ctx *ctx) void gwp_dns_ctx_free(struct gwp_dns_ctx *ctx) { - free_workers(ctx); + if (ctx->cfg.use_raw_dns) { +#ifdef CONFIG_RAW_DNS + free_all_queued_entries(ctx); +#endif + } else { + free_workers(ctx); + pthread_cond_destroy(&ctx->cond); + put_all_queued_entries(ctx); + } pthread_mutex_destroy(&ctx->lock); - pthread_cond_destroy(&ctx->cond); - put_all_queued_entries(ctx); free_cache(ctx->cache); free(ctx); } @@ -791,14 +931,51 @@ struct gwp_dns_entry *gwp_dns_queue(struct gwp_dns_ctx *ctx, { struct gwp_dns_entry *e; size_t nl, sl; +#ifdef CONFIG_RAW_DNS + uint16_t txid; + ssize_t r; + int af; +#endif e = malloc(sizeof(*e)); if (!e) return NULL; - e->ev_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); - if (e->ev_fd < 0) - goto out_free_e; + if (ctx->cfg.use_raw_dns) { +#ifdef CONFIG_RAW_DNS + if (ctx->nr_entries == ctx->entry_cap && realloc_entries(ctx)) + return NULL; + + r = __sys_socket(ctx->ns_addr.sa.sa_family, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (r < 0) + goto out_free_e; + e->udp_fd = (int)r; + + switch (ctx->cfg.restyp) { + case GWP_DNS_RESTYP_PREFER_IPV4: + case GWP_DNS_RESTYP_IPV4_ONLY: + af = AF_INET; + break; + case GWP_DNS_RESTYP_PREFER_IPV6: + case GWP_DNS_RESTYP_IPV6_ONLY: + af = AF_INET6; + break; + default: + assert(0); + break; + } + + txid = (uint16_t)rand(); + r = gwdns_build_query(txid, name, af, e->payload, sizeof(e->payload)); + if (r < 0) + goto out_free_e; + e->payloadlen = (int)r; +#endif + } else { + e->ev_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (e->ev_fd < 0) + goto out_free_e; + } /* * Merge name and service into a single allocated string to @@ -811,7 +988,7 @@ struct gwp_dns_entry *gwp_dns_queue(struct gwp_dns_ctx *ctx, sl = service ? strlen(service) : 0; e->name = malloc(nl + 1 + sl + 1); if (!e->name) - goto out_close_ev_fd; + goto out_close_fd; e->service = e->name + nl + 1; memcpy(e->name, name, nl + 1); @@ -820,13 +997,26 @@ struct gwp_dns_entry *gwp_dns_queue(struct gwp_dns_ctx *ctx, else e->service[0] = '\0'; - atomic_init(&e->refcnt, 2); e->res = 0; - push_queue(ctx, e); + if (ctx->cfg.use_raw_dns) { +#ifdef CONFIG_RAW_DNS + e->idx = ctx->nr_entries++; + ctx->entries[e->idx] = e; +#endif + } else { + atomic_init(&e->refcnt, 2); + push_queue(ctx, e); + } return e; -out_close_ev_fd: - close(e->ev_fd); +out_close_fd: + if (ctx->cfg.use_raw_dns) { +#ifdef CONFIG_RAW_DNS + close(e->udp_fd); +#endif + } else { + close(e->ev_fd); + } out_free_e: free(e); return NULL; diff --git a/src/gwproxy/dns.h b/src/gwproxy/dns.h index 10c7cea2ebe4..410989f6414c 100644 --- a/src/gwproxy/dns.h +++ b/src/gwproxy/dns.h @@ -10,10 +10,19 @@ #include #include #include - -struct gwp_dns_wrk; +#include +#include struct gwp_dns_entry { +#ifdef CONFIG_RAW_DNS + uint32_t idx; + int udp_fd; + int payloadlen; + union { + uint16_t txid; + uint8_t payload[UDP_MSG_LIMIT]; + }; +#endif char *name; char *service; _Atomic(int) refcnt; @@ -31,10 +40,16 @@ enum { GWP_DNS_RESTYP_PREFER_IPV6 = 4, }; +#define DEFAULT_ENTRIES_CAP 255 + struct gwp_dns_cfg { int cache_expiry; /* In seconds. <= 0 to disable cache. */ uint32_t nr_workers; uint32_t restyp; + bool use_raw_dns; +#ifdef CONFIG_RAW_DNS + const char *ns_addr_str; +#endif }; struct gwp_dns_ctx; @@ -76,7 +91,6 @@ void gwp_dns_ctx_free(struct gwp_dns_ctx *ctx); */ struct gwp_dns_entry *gwp_dns_queue(struct gwp_dns_ctx *ctx, const char *name, const char *service); - /** * Release a DNS entry. This function decrements the reference count of the * entry. If the reference count reaches zero, the entry is freed. @@ -87,6 +101,15 @@ struct gwp_dns_entry *gwp_dns_queue(struct gwp_dns_ctx *ctx, */ bool gwp_dns_entry_put(struct gwp_dns_entry *entry); +#ifdef CONFIG_RAW_DNS + +void cp_nsaddr(struct gwp_dns_ctx *ctx, struct gwp_sockaddr *addr, uint8_t *addrlen); + +void gwp_dns_raw_entry_free(struct gwp_dns_ctx *ctx, struct gwp_dns_entry *e); + +int gwp_dns_process(struct gwp_dns_ctx *ctx, struct gwp_dns_entry *e); +#endif + /** * Lookup a DNS entry in the cache. If the entry is found, it fills the * `addr` structure with the resolved address and returns 0. If the entry is diff --git a/src/gwproxy/ev/epoll.c b/src/gwproxy/ev/epoll.c index d46568a6a2b1..d824aeec2958 100644 --- a/src/gwproxy/ev/epoll.c +++ b/src/gwproxy/ev/epoll.c @@ -778,24 +778,55 @@ static int handle_connect(struct gwp_wrk *w, struct gwp_conn_pair *gcp) return 0; } +#ifdef CONFIG_RAW_DNS +static int arm_poll_for_raw_dns_query(struct gwp_wrk *w, + struct gwp_conn_pair *gcp) +{ + struct gwp_dns_entry *gde = gcp->gde; + struct gwp_dns_ctx *dctx; + struct gwp_sockaddr addr; + uint8_t addrlen; + ssize_t r; + + dctx = w->ctx->dns; + cp_nsaddr(dctx, &addr, &addrlen); + r = __sys_sendto( + gde->udp_fd, gde->payload, gde->payloadlen, MSG_NOSIGNAL, + &addr.sa, addrlen + ); + + return (int)r; +} +#endif + static int arm_poll_for_dns_query(struct gwp_wrk *w, struct gwp_conn_pair *gcp) { struct gwp_dns_entry *gde = gcp->gde; struct epoll_event ev; - int r; + ssize_t r; assert(gde); - assert(gde->ev_fd >= 0); ev.events = EPOLLIN; ev.data.u64 = 0; ev.data.ptr = gcp; ev.data.u64 |= EV_BIT_DNS_QUERY; - r = __sys_epoll_ctl(w->ep_fd, EPOLL_CTL_ADD, gde->ev_fd, &ev); + if (w->ctx->cfg.use_raw_dns) { +#ifdef CONFIG_RAW_DNS + arm_poll_for_raw_dns_query(w, gcp); + + r = __sys_epoll_ctl(w->ep_fd, EPOLL_CTL_ADD, gde->udp_fd, &ev); if (unlikely(r)) - return r; + return (int)r; +#endif + } else { + assert(gde->ev_fd >= 0); + r = __sys_epoll_ctl(w->ep_fd, EPOLL_CTL_ADD, gde->ev_fd, &ev); + if (unlikely(r)) + return (int)r; + } return 0; } @@ -826,13 +857,25 @@ static int handle_ev_dns_query(struct gwp_wrk *w, struct gwp_conn_pair *gcp) int r, ct = gcp->conn_state; assert(gde); - assert(gde->ev_fd >= 0); assert(ct == CONN_STATE_SOCKS5_DNS_QUERY || ct == CONN_STATE_HTTP_DNS_QUERY); - r = __sys_epoll_ctl(w->ep_fd, EPOLL_CTL_DEL, gde->ev_fd, NULL); - if (unlikely(r)) - return r; + if (w->ctx->cfg.use_raw_dns) { +#ifdef CONFIG_RAW_DNS + r = gwp_dns_process(w->ctx->dns, gde); + if (r == -EAGAIN) { + pr_dbg(&w->ctx->lh, "DNS Fallback"); + arm_poll_for_raw_dns_query(w, gcp); + return 0; + } else if (r) + gde->res = r; +#endif + } else { + assert(gde->ev_fd >= 0); + r = __sys_epoll_ctl(w->ep_fd, EPOLL_CTL_DEL, gde->ev_fd, NULL); + if (unlikely(r)) + return r; + } log_dns_query(w, gcp, gde); if (likely(!gde->res)) { @@ -844,8 +887,14 @@ static int handle_ev_dns_query(struct gwp_wrk *w, struct gwp_conn_pair *gcp) else r = -EIO; } - - gwp_dns_entry_put(gde); + + if (w->ctx->cfg.use_raw_dns) { +#ifdef CONFIG_RAW_DNS + gwp_dns_raw_entry_free(w->ctx->dns, gde); +#endif + } else { + gwp_dns_entry_put(gde); + } gcp->gde = NULL; return r; } diff --git a/src/gwproxy/gwproxy.c b/src/gwproxy/gwproxy.c index 7a90609dd5f1..36305e65c4cb 100644 --- a/src/gwproxy/gwproxy.c +++ b/src/gwproxy/gwproxy.c @@ -44,6 +44,10 @@ static const struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, + { "raw-dns", required_argument, NULL, 'r' }, +#ifdef CONFIG_RAW_DNS + { "dns-server", required_argument, NULL, 'j' }, +#endif { "event-loop", required_argument, NULL, 'e' }, { "bind", required_argument, NULL, 'b' }, { "target", required_argument, NULL, 't' }, @@ -54,7 +58,6 @@ static const struct option long_opts[] = { { "socks5-auth-file", required_argument, NULL, 'A' }, { "socks5-dns-cache-secs", required_argument, NULL, 'L' }, { "nr-workers", required_argument, NULL, 'w' }, - { "nr-dns-workers", required_argument, NULL, 'W' }, { "connect-timeout", required_argument, NULL, 'c' }, { "target-buf-size", required_argument, NULL, 'T' }, { "client-buf-size", required_argument, NULL, 'C' }, @@ -74,6 +77,7 @@ static const struct gwp_cfg default_opts = { .event_loop = "epoll", .bind = "[::]:1080", .target = NULL, + .use_raw_dns = false, .as_socks5 = false, .as_http = false, .socks5_prefer_ipv6 = false, @@ -81,7 +85,6 @@ static const struct gwp_cfg default_opts = { .socks5_auth_file = NULL, .socks5_dns_cache_secs = 0, .nr_workers = 4, - .nr_dns_workers = 4, .connect_timeout = 5, .target_buf_size = 2048, .client_buf_size = 2048, @@ -94,6 +97,9 @@ static const struct gwp_cfg default_opts = { .log_level = 3, .log_file = "/dev/stdout", .pid_file = NULL, +#ifdef CONFIG_RAW_DNS + .ns_addr_str = "1.1.1.1" +#endif }; __cold @@ -104,6 +110,10 @@ static void show_help(const char *app) printf(" -h, --help Show this help message and exit\n"); printf(" -e, --event-loop=name Specify the event loop to use (default: %s)\n", default_opts.event_loop); printf(" Available values: epoll, io_uring\n"); + printf(" -r, --raw-dns=0|1 Use experimental raw DNS as the backend (default: %d)\n", default_opts.use_raw_dns); +#ifdef CONFIG_RAW_DNS + printf(" -j, --dns-server=addr DNS server address (default: %s)\n", default_opts.ns_addr_str); +#endif printf(" -b, --bind=addr:port Bind to the specified address (default: %s)\n", default_opts.bind); printf(" -t, --target=addr_port Target address to connect to\n"); printf(" -S, --as-socks5=0|1 Run as a SOCKS5 proxy (default: %d)\n", default_opts.as_socks5); @@ -114,7 +124,6 @@ static void show_help(const char *app) printf(" -L, --socks5-dns-cache-secs=sec SOCKS5 DNS cache duration in seconds (default: %d)\n", default_opts.socks5_dns_cache_secs); printf(" Set to 0 or a negative number to disable DNS caching.\n"); printf(" -w, --nr-workers=nr Number of worker threads (default: %d)\n", default_opts.nr_workers); - printf(" -W, --nr-dns-workers=nr Number of DNS worker threads for SOCKS5 (default: %d)\n", default_opts.nr_dns_workers); printf(" -c, --connect-timeout=sec Connection to target timeout in seconds (default: %d)\n", default_opts.connect_timeout); printf(" -T, --target-buf-size=nr Target buffer size in bytes (default: %d)\n", default_opts.target_buf_size); printf(" -C, --client-buf-size=nr Client buffer size in bytes (default: %d)\n", default_opts.client_buf_size); @@ -159,6 +168,9 @@ static int parse_options(int argc, char *argv[], struct gwp_cfg *cfg) case 'h': show_help(argv[0]); exit(0); + case 'r': + cfg->use_raw_dns = !!atoi(optarg); + break; case 'e': cfg->event_loop = optarg; break; @@ -189,9 +201,6 @@ static int parse_options(int argc, char *argv[], struct gwp_cfg *cfg) case 'w': cfg->nr_workers = atoi(optarg); break; - case 'W': - cfg->nr_dns_workers = atoi(optarg); - break; case 'c': cfg->connect_timeout = atoi(optarg); break; @@ -228,6 +237,11 @@ static int parse_options(int argc, char *argv[], struct gwp_cfg *cfg) case 'p': cfg->pid_file = optarg; break; +#ifdef CONFIG_RAW_DNS + case 'j': + cfg->ns_addr_str = optarg; + break; +#endif default: fprintf(stderr, "Unknown option: %c\n", c); show_help(argv[0]); @@ -689,12 +703,23 @@ static int gwp_ctx_init_dns(struct gwp_ctx *ctx) { struct gwp_cfg *cfg = &ctx->cfg; const struct gwp_dns_cfg dns_cfg = { + .use_raw_dns = cfg->use_raw_dns, .cache_expiry = cfg->socks5_dns_cache_secs, .restyp = cfg->socks5_prefer_ipv6 ? GWP_DNS_RESTYP_PREFER_IPV6 : 0, - .nr_workers = cfg->nr_dns_workers + .nr_workers = 1, +#ifdef CONFIG_RAW_DNS + .ns_addr_str = cfg->ns_addr_str +#endif }; int r; + if (cfg->use_raw_dns) { +#ifndef CONFIG_RAW_DNS + pr_err(&ctx->lh, "raw DNS backend is not enabled in this build"); + return -ENOSYS; +#endif + } + if (!cfg->as_socks5 && !cfg->as_http) { ctx->dns = NULL; return 0; @@ -733,6 +758,10 @@ static int gwp_ctx_parse_ev(struct gwp_ctx *ctx) ctx->ev_used = GWP_EV_EPOLL; pr_dbg(&ctx->lh, "Using event loop: epoll"); } else if (!strcmp(ev, "io_uring") || !strcmp(ev, "iou")) { + if (ctx->cfg.use_raw_dns) { + pr_err(&ctx->lh, "raw DNS backend is not supported for io_uring yet"); + return -ENOSYS; + } ctx->ev_used = GWP_EV_IO_URING; pr_dbg(&ctx->lh, "Using event loop: io_uring"); } else { @@ -990,8 +1019,15 @@ int gwp_free_conn_pair(struct gwp_wrk *w, struct gwp_conn_pair *gcp) if (gcp->timer_fd >= 0) __sys_close(gcp->timer_fd); - if (gcp->gde) - gwp_dns_entry_put(gcp->gde); + if (gcp->gde) { + if (w->ctx->cfg.use_raw_dns) { +#ifdef CONFIG_RAW_DNS + gwp_dns_raw_entry_free(w->ctx->dns, gcp->gde); +#endif + } else { + gwp_dns_entry_put(gcp->gde); + } + } switch (gcp->prot_type) { case GWP_PROT_TYPE_SOCKS5: diff --git a/src/gwproxy/gwproxy.h b/src/gwproxy/gwproxy.h index 095c0ce700c3..cdc5adf88ad6 100644 --- a/src/gwproxy/gwproxy.h +++ b/src/gwproxy/gwproxy.h @@ -24,6 +24,7 @@ struct gwp_cfg { const char *event_loop; const char *bind; const char *target; + bool use_raw_dns; bool as_socks5; bool as_http; bool socks5_prefer_ipv6; @@ -31,7 +32,6 @@ struct gwp_cfg { const char *socks5_auth_file; int socks5_dns_cache_secs; int nr_workers; - int nr_dns_workers; int connect_timeout; int target_buf_size; int client_buf_size; @@ -44,6 +44,9 @@ struct gwp_cfg { int log_level; const char *log_file; const char *pid_file; +#ifdef CONFIG_RAW_DNS + const char *ns_addr_str; +#endif }; struct gwp_ctx; -- Ahmad Gani