From: Ahmad Gani <reyuki@gnuweeb.org>
To: Ammar Faizi <ammarfaizi2@gnuweeb.org>
Cc: Ahmad Gani <reyuki@gnuweeb.org>,
Alviro Iskandar Setiawan <alviro.iskandar@gnuweeb.org>,
GNU/Weeb Mailing List <gwml@vger.gnuweeb.org>
Subject: [PATCH gwproxy v8 2/2] gwproxy: refactor code base to add experimental raw DNS backend
Date: Fri, 29 Aug 2025 14:55:54 +0700 [thread overview]
Message-ID: <20250829075557.598176-3-reyuki@gnuweeb.org> (raw)
In-Reply-To: <20250829075557.598176-1-reyuki@gnuweeb.org>
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 <reyuki@gnuweeb.org>
---
Makefile | 2 +-
configure | 8 ++
src/gwproxy/dns.c | 241 ++++++++++++++++++++++++++++++++++++-----
src/gwproxy/dns.h | 29 ++++-
src/gwproxy/ev/epoll.c | 67 ++++++++++--
src/gwproxy/gwproxy.c | 54 +++++++--
src/gwproxy/gwproxy.h | 5 +-
7 files changed, 357 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..f22738c912e4 100644
--- a/src/gwproxy/dns.c
+++ b/src/gwproxy/dns.c
@@ -23,6 +23,7 @@
#include <pthread.h>
#include <sys/eventfd.h>
+#include <gwproxy/dnsparser.h>
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,13 +191,122 @@ 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);
+ __sys_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;
+ }
+
+ 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)
return;
assert(e->ev_fd >= 0);
- close(e->ev_fd);
+ __sys_close(e->ev_fd);
free(e->name);
free(e);
}
@@ -719,33 +837,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 +895,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 +930,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);
+ goto out_close_fd;
+ }
+
+ txid = (uint16_t)rand();
+ r = gwdns_build_query(txid, name, af, e->payload, sizeof(e->payload));
+ if (r < 0)
+ goto out_close_fd;
+ 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 +987,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 +996,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
+ __sys_close(e->udp_fd);
+#endif
+ } else {
+ __sys_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 <stdbool.h>
#include <netinet/in.h>
#include <gwproxy/net.h>
-
-struct gwp_dns_wrk;
+#include <gwproxy/dnsparser.h>
+#include <gwproxy/syscall.h>
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..357f9a3e0486 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)) {
@@ -845,7 +888,13 @@ static int handle_ev_dns_query(struct gwp_wrk *w, struct gwp_conn_pair *gcp)
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
prev parent reply other threads:[~2025-08-29 7:56 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-29 7:55 [PATCH gwproxy v8 0/2] Initial work on integration of DNS parser lib in gwproxy Ahmad Gani
2025-08-29 7:55 ` [PATCH gwproxy v8 1/2] dnsparser: Add dns parser code Ahmad Gani
2025-08-29 7:55 ` Ahmad Gani [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250829075557.598176-3-reyuki@gnuweeb.org \
--to=reyuki@gnuweeb.org \
--cc=alviro.iskandar@gnuweeb.org \
--cc=ammarfaizi2@gnuweeb.org \
--cc=gwml@vger.gnuweeb.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox