* [PATCH gwproxy v11 1/6] dns: Use __sys_close instead of close
2025-09-14 5:09 [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ahmad Gani
@ 2025-09-14 5:09 ` Ahmad Gani
2025-09-14 5:09 ` [PATCH gwproxy v11 2/6] gwproxy: Define __maybe_unused macro Ahmad Gani
` (6 subsequent siblings)
7 siblings, 0 replies; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 5:09 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Ahmad Gani, Alviro Iskandar Setiawan, GNU/Weeb Mailing List
Signed-off-by: Ahmad Gani <reyuki@gnuweeb.org>
---
src/gwproxy/dns.c | 4 ++--
src/gwproxy/dns.h | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/gwproxy/dns.c b/src/gwproxy/dns.c
index cdc62a5bcf78..bd8c90fb1449 100644
--- a/src/gwproxy/dns.c
+++ b/src/gwproxy/dns.c
@@ -188,7 +188,7 @@ static void gwp_dns_entry_free(struct gwp_dns_entry *e)
return;
assert(e->ev_fd >= 0);
- close(e->ev_fd);
+ __sys_close(e->ev_fd);
free(e->name);
free(e);
}
@@ -826,7 +826,7 @@ struct gwp_dns_entry *gwp_dns_queue(struct gwp_dns_ctx *ctx,
return e;
out_close_ev_fd:
- close(e->ev_fd);
+ __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..420a80e5cf6a 100644
--- a/src/gwproxy/dns.h
+++ b/src/gwproxy/dns.h
@@ -10,6 +10,7 @@
#include <stdbool.h>
#include <netinet/in.h>
#include <gwproxy/net.h>
+#include <gwproxy/syscall.h>
struct gwp_dns_wrk;
--
Ahmad Gani
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH gwproxy v11 2/6] gwproxy: Define __maybe_unused macro
2025-09-14 5:09 [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ahmad Gani
2025-09-14 5:09 ` [PATCH gwproxy v11 1/6] dns: Use __sys_close instead of close Ahmad Gani
@ 2025-09-14 5:09 ` Ahmad Gani
2025-09-14 5:09 ` [PATCH gwproxy v11 3/6] dnsparser: Add dns parser code Ahmad Gani
` (5 subsequent siblings)
7 siblings, 0 replies; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 5:09 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Ahmad Gani, Alviro Iskandar Setiawan, GNU/Weeb Mailing List
Useful to reduce #ifdef guard.
Link: https://lore.gnuweeb.org/gwml/CAADvAgrOqqEdjJ6gN3sq05iTBpMFAx5Ygx8PQ=TW+FisCATiMA@mail.gmail.com/
Signed-off-by: Ahmad Gani <reyuki@gnuweeb.org>
---
src/gwproxy/common.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/gwproxy/common.h b/src/gwproxy/common.h
index 8ae6ab4a31f5..aae4446a6875 100644
--- a/src/gwproxy/common.h
+++ b/src/gwproxy/common.h
@@ -12,6 +12,10 @@
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((__unused__))
+#endif
+
#ifndef __cold
#define __cold __attribute__((__cold__))
#endif
--
Ahmad Gani
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH gwproxy v11 3/6] dnsparser: Add dns parser code
2025-09-14 5:09 [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ahmad Gani
2025-09-14 5:09 ` [PATCH gwproxy v11 1/6] dns: Use __sys_close instead of close Ahmad Gani
2025-09-14 5:09 ` [PATCH gwproxy v11 2/6] gwproxy: Define __maybe_unused macro Ahmad Gani
@ 2025-09-14 5:09 ` Ahmad Gani
2025-09-14 5:09 ` [PATCH gwproxy v11 4/6] gwproxy: Refactor code base to add experimental raw DNS backend Ahmad Gani
` (4 subsequent siblings)
7 siblings, 0 replies; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 5:09 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Ahmad Gani, Alviro Iskandar Setiawan, GNU/Weeb Mailing List
Introducing dns parser for better flexibility over the program flow, the
DNS protocol implementation is limited to standard query (OPCODE_QUERY).
Delegate creation of transaction id to the caller, It gives the caller
more flexibility in handling DNS requests.
A single domain name lookup can have two responses: one for IPv4 and one
for IPv6. The caller may use the same txid for both queries.
Signed-off-by: Ahmad Gani <reyuki@gnuweeb.org>
---
src/gwproxy/dnsparser.c | 583 ++++++++++++++++++++++++++++++++++++++++
src/gwproxy/dnsparser.h | 192 +++++++++++++
2 files changed, 775 insertions(+)
create mode 100644 src/gwproxy/dnsparser.c
create mode 100644 src/gwproxy/dnsparser.h
diff --git a/src/gwproxy/dnsparser.c b/src/gwproxy/dnsparser.c
new file mode 100644
index 000000000000..973a189bed19
--- /dev/null
+++ b/src/gwproxy/dnsparser.c
@@ -0,0 +1,583 @@
+#define _DEFAULT_SOURCE
+#include <endian.h>
+#include <stdbool.h>
+#include <gwproxy/dnsparser.h>
+#include <gwproxy/net.h>
+
+static ssize_t construct_qname(uint8_t *dst, size_t dst_len, const char *qname)
+{
+ const uint8_t *p = (const uint8_t *)qname;
+ uint8_t *lp = dst; /* Length position. */
+ uint8_t *sp = lp + 1; /* String position. */
+ size_t total = 0;
+ uint16_t l = 0;
+
+ while (1) {
+ uint8_t c = *p++;
+
+ total++;
+ if (total >= dst_len)
+ return -ENAMETOOLONG;
+
+ if (c == '.' || c == '\0') {
+ if (l < 1 || l > DOMAIN_LABEL_LIMIT)
+ return -EINVAL;
+
+ *lp = (uint8_t)l;
+ lp = sp++;
+ l = 0;
+ if (!c)
+ break;
+ } else {
+ l++;
+ *sp = c;
+ sp++;
+ }
+ }
+
+ return total;
+}
+
+static int calculate_question_len(uint8_t *in, size_t in_len)
+{
+ const uint8_t *p = in;
+ int tot_len, advance_len;
+
+ tot_len = 0;
+ while (true) {
+ if (*p == 0x0) {
+ tot_len++;
+ break;
+ }
+
+ if (tot_len >= (int)in_len)
+ return -ENOBUFS;
+
+ advance_len = *p + 1;
+ tot_len += advance_len;
+ p += advance_len;
+ }
+
+ if (tot_len > DOMAIN_NAME_LIMIT)
+ return -ENAMETOOLONG;
+
+ tot_len += 4;
+ if (tot_len >= (int)in_len)
+ return -ENOBUFS;
+
+ return tot_len;
+}
+
+static int serialize_answ(uint16_t txid, uint8_t *in, size_t in_len, gwdns_answ_data *out)
+{
+ gwdns_header_pkt *hdr;
+ uint16_t raw_flags;
+ size_t idx, i;
+ void *ptr;
+ int ret;
+
+ idx = sizeof(*hdr);
+ if (idx >= in_len)
+ return -EAGAIN;
+
+ hdr = (void *)in;
+ if (memcmp(&txid, &hdr->id, sizeof(txid)))
+ return -EINVAL;
+
+ memcpy(&raw_flags, &hdr->flags, sizeof(raw_flags));
+ raw_flags = ntohs(raw_flags);
+ /* QR MUST 1 = response from dns server */
+ if (!DNS_QR(raw_flags))
+ return -EINVAL;
+
+ /* OPCODE MUST 0 = standard query */
+ if (DNS_OPCODE(raw_flags))
+ return -EINVAL;
+
+ /* RCODE MUST 0 = No error */
+ if (DNS_RCODE(raw_flags))
+ return -EPROTO;
+
+ // is it safe or recommended to alter the in buffer directly?
+ hdr->ancount = ntohs(hdr->ancount);
+ if (!hdr->ancount)
+ return -ENODATA;
+
+ /*
+ * Check the sizes upfront.
+ *
+ * 1 bytes for variable-length
+ * in[idx] for the length of first name
+ * 1 bytes for null terminator
+ * 2 bytes for qtype
+ * 2 bytes for qclass
+ */
+ if ((size_t)(1 + in[idx] + 1 + 2 + 2) >= in_len)
+ return -EINVAL;
+
+ ret = calculate_question_len(&in[idx], in_len - idx);
+ if (ret <= 0)
+ return -EINVAL;
+
+ idx += ret;
+ if (idx >= in_len)
+ return -EAGAIN;
+
+ out->hdr.ancount = 0;
+ ptr = malloc(hdr->ancount * sizeof(uint8_t *));
+ if (!ptr)
+ return -ENOMEM;
+
+ out->rr_answ = ptr;
+ for (i = 0; i < hdr->ancount; i++) {
+ uint16_t is_compressed, rdlength;
+ gwdns_serialized_answ *item = malloc(sizeof(gwdns_serialized_answ));
+ if (!item) {
+ ret = -ENOMEM;
+ goto exit_free;
+ }
+
+ memcpy(&is_compressed, &in[idx], sizeof(is_compressed));
+ is_compressed = ntohs(is_compressed);
+ is_compressed = DNS_IS_COMPRESSED(is_compressed);
+ assert(is_compressed);
+ idx += 2; // NAME
+ if (idx >= in_len) {
+ ret = -EAGAIN;
+ free(item);
+ goto exit_free;
+ }
+
+ memcpy(&item->rr_type, &in[idx], 2);
+ item->rr_type = ntohs(item->rr_type);
+ idx += 2; // TYPE
+ if (idx >= in_len) {
+ ret = -EAGAIN;
+ free(item);
+ goto exit_free;
+ }
+ memcpy(&item->rr_class, &in[idx], 2);
+ item->rr_class = ntohs(item->rr_class);
+ idx += 2; // CLASS
+ if (idx >= in_len) {
+ ret = -EAGAIN;
+ free(item);
+ goto exit_free;
+ }
+ memcpy(&item->ttl, &in[idx], 4);
+ item->ttl = be32toh(item->ttl);
+ idx += 4; // TTL
+ if (idx >= in_len) {
+ ret = -EAGAIN;
+ free(item);
+ goto exit_free;
+ }
+
+ memcpy(&rdlength, &in[idx], sizeof(rdlength));
+ rdlength = ntohs(rdlength);
+ switch (item->rr_type) {
+ case TYPE_AAAA:
+ if (rdlength != sizeof(struct in6_addr)) {
+ ret = -EINVAL;
+ free(item);
+ goto exit_free;
+ }
+ break;
+ case TYPE_A:
+ if (rdlength != sizeof(struct in_addr)) {
+ ret = -EINVAL;
+ free(item);
+ goto exit_free;
+ }
+ break;
+ case TYPE_CNAME:
+ idx += 2 + rdlength;
+ free(item);
+ continue;
+
+ default:
+ ret = -EINVAL;
+ free(item);
+ goto exit_free;
+ break;
+ }
+
+ item->rdlength = rdlength;
+ idx += 2;
+ if (idx >= in_len) {
+ ret = -EAGAIN;
+ free(item);
+ goto exit_free;
+ }
+
+ ptr = malloc(rdlength);
+ if (!ptr) {
+ ret = -ENOMEM;
+ free(item);
+ goto exit_free;
+ }
+
+ memcpy(ptr, &in[idx], rdlength);
+ idx += rdlength;
+ if (idx > in_len) {
+ ret = -EINVAL;
+ free(item);
+ free(ptr);
+ goto exit_free;
+ }
+
+ item->rdata = ptr;
+ out->rr_answ[out->hdr.ancount] = item;
+ out->hdr.ancount++;
+ }
+
+ if (!out->hdr.ancount) {
+ free(out->rr_answ);
+ return -ENODATA;
+ }
+
+ return 0;
+exit_free:
+ for (i = 0; i < out->hdr.ancount; i++) {
+ free(out->rr_answ[i]->rdata);
+ free(out->rr_answ[i]);
+ }
+ free(out->rr_answ);
+ return ret;
+}
+
+static void free_serialize_answ(gwdns_answ_data *answ)
+{
+ size_t i;
+ for (i = 0; i < answ->hdr.ancount; i++) {
+ free(answ->rr_answ[i]->rdata);
+ free(answ->rr_answ[i]);
+ }
+ free(answ->rr_answ);
+}
+
+int gwdns_parse_query(uint16_t txid, const char *service,
+ uint8_t *in, size_t in_len,
+ struct gwdns_addrinfo_node **ai)
+{
+ struct gwdns_addrinfo_node *results, *tail;
+ gwdns_answ_data raw_answ;
+ int r, port;
+ size_t i;
+
+ port = atoi(service);
+ if (port < 0)
+ return -EINVAL;
+ port = htons(port);
+
+ r = serialize_answ(txid, in, in_len, &raw_answ);
+ if (r)
+ return r;
+
+ results = tail = NULL;
+ for (i = 0; i < raw_answ.hdr.ancount; i++) {
+ struct gwdns_addrinfo_node *new_node;
+ gwdns_serialized_answ *answ;
+ struct sockaddr_in6 *i6;
+ struct sockaddr_in *i4;
+
+ answ = raw_answ.rr_answ[i];
+ new_node = malloc(sizeof(*new_node));
+ if (!new_node) {
+ r = -ENOMEM;
+ goto exit_free;
+ }
+ new_node->ai_next = NULL;
+
+ if (answ->rr_type == TYPE_AAAA) {
+ i6 = &new_node->ai_addr.i6;
+ new_node->ai_family = AF_INET6;
+ new_node->ai_addrlen = sizeof(i6);
+ i6->sin6_port = port;
+ i6->sin6_family = AF_INET6;
+ assert(sizeof(i6->sin6_addr) == answ->rdlength);
+ memcpy(&i6->sin6_addr, answ->rdata, answ->rdlength);
+ } else {
+ i4 = &new_node->ai_addr.i4;
+ new_node->ai_family = AF_INET;
+ new_node->ai_addrlen = sizeof(i4);
+ i4->sin_port = port;
+ i4->sin_family = AF_INET;
+ assert(sizeof(i4->sin_addr) == answ->rdlength);
+ memcpy(&i4->sin_addr, answ->rdata, answ->rdlength);
+ new_node->ai_ttl = answ->ttl;
+ }
+
+ if (!tail)
+ results = new_node;
+ else
+ tail->ai_next = new_node;
+ tail = new_node;
+ }
+
+ *ai = results;
+ r = 0;
+exit_free:
+ if (r && results)
+ gwdns_free_parsed_query(results);
+ free_serialize_answ(&raw_answ);
+ return r;
+}
+
+void gwdns_free_parsed_query(struct gwdns_addrinfo_node *ai)
+{
+ struct gwdns_addrinfo_node *tmp, *node = ai;
+ while (node) {
+ tmp = node->ai_next;
+ free(node);
+ node = tmp;
+ }
+}
+
+static ssize_t construct_question(gwdns_question_part *question)
+{
+ gwdns_header_pkt *hdr;
+ gwdns_query_pkt pkt;
+ uint16_t qtype, qclass;
+ size_t required_len;
+ ssize_t bw;
+
+ switch (question->type) {
+ case AF_INET6:
+ question->type = TYPE_AAAA;
+ break;
+ case AF_INET:
+ question->type = TYPE_A;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ hdr = &pkt.hdr;
+ /*
+ * the memset implicitly set opcode to OPCODE_QUERY
+ */
+ memset(hdr, 0, sizeof(*hdr));
+ /*
+ * no need to htons, so no ntohs for comparison in serialize_answ.
+ */
+ hdr->id = question->txid;
+ DNS_SET_RD(hdr->flags, true);
+ hdr->flags = htons(hdr->flags);
+ hdr->qdcount = htons(1);
+
+ /*
+ * pkt.body is interpreted as question section
+ * for layout and format, see RFC 1035 4.1.2. Question section format
+ */
+ bw = construct_qname(pkt.body, sizeof(pkt.body) - 3, question->domain);
+ if (bw < 0)
+ return bw;
+
+ pkt.body[bw++] = 0x0;
+ qtype = htons(question->type);
+ qclass = htons(CLASS_IN);
+ memcpy(&pkt.body[bw], &qtype, 2);
+ bw += 2;
+ memcpy(&pkt.body[bw], &qclass, 2);
+ bw += 2;
+
+ required_len = sizeof(pkt.hdr) + bw;
+ if (question->dst_len < required_len)
+ return -ENOBUFS;
+
+ memcpy(question->dst_buffer, &pkt, required_len);
+
+ return required_len;
+}
+
+ssize_t gwdns_build_query(uint16_t txid, const char *name, int family, uint8_t *out, size_t out_len)
+{
+ gwdns_question_part q;
+
+ q.domain = name;
+ q.type = family;
+ q.txid = txid;
+ q.dst_buffer = out;
+ q.dst_len = out_len;
+ return construct_question(&q);
+}
+
+#ifdef RUNTEST
+
+void test_parse_ipv4(void)
+{
+ struct gwdns_addrinfo_node *d, *node;
+ uint16_t txid;
+
+ uint8_t recv_pkt[] = {
+ 0x23, 0xc6, 0x81, 0x80, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
+ 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x35, 0x00, 0x04, 0x4a, 0x7d, 0x18, 0x8a, 0xc0, 0x0c, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x35, 0x00, 0x04, 0x4a, 0x7d, 0x18, 0x66,
+ 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x35, 0x00, 0x04,
+ 0x4a, 0x7d, 0x18, 0x64, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x35, 0x00, 0x04, 0x4a, 0x7d, 0x18, 0x8b, 0xc0, 0x0c, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x35, 0x00, 0x04, 0x4a, 0x7d, 0x18, 0x65,
+ 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x35, 0x00, 0x04,
+ 0x4a, 0x7d, 0x18, 0x71
+ };
+
+ memcpy(&txid, recv_pkt, 2);
+ d = NULL;
+ assert(!gwdns_parse_query(txid, "80", recv_pkt, sizeof(recv_pkt), &d));
+ assert(d);
+ node = d;
+ while (node) {
+ struct gwdns_addrinfo_node *tmp;
+ char buff[FULL_ADDRSTRLEN];
+
+ tmp = node->ai_next;
+ assert(node->ai_family == AF_INET);
+ convert_ssaddr_to_str(buff, &node->ai_addr);
+ printf("IPv4: %s\n", buff);
+ node = tmp;
+ }
+
+ gwdns_free_parsed_query(d);
+}
+
+void test_parse_ipv6(void)
+{
+ struct gwdns_addrinfo_node *d, *node;
+ uint16_t txid;
+
+ uint8_t recv_pkt[] = {
+ 0x45, 0x67,
+ 0x81, 0x80,
+ 0x00, 0x01,
+ 0x00, 0x04,
+ 0x00, 0x00,
+ 0x00, 0x00,
+
+ 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x03, 0x63, 0x6f, 0x6d,
+ 0x00,
+ 0x00, 0x1c,
+ 0x00, 0x01,
+
+ 0xc0, 0x0c,
+ 0x00, 0x1c,
+ 0x00, 0x01,
+ 0x00, 0x00, 0x09, 0x06,
+ 0x00, 0x10,
+ 0x24, 0x04, 0x68, 0x00, 0x40, 0x03, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71,
+
+ 0xc0, 0x0c,
+ 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x09, 0x06,
+ 0x00, 0x10,
+ 0x24, 0x04, 0x68, 0x00, 0x40, 0x03, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a,
+
+ 0xc0, 0x0c,
+ 0x00, 0x1c,
+ 0x00, 0x01,
+ 0x00, 0x00, 0x09, 0x06,
+ 0x00, 0x10,
+ 0x24, 0x04, 0x68, 0x00, 0x40, 0x03, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
+
+ 0xc0, 0x0c,
+ 0x00, 0x1c,
+ 0x00, 0x01,
+ 0x00, 0x00, 0x0c, 0x16,
+ 0x00, 0x10,
+ 0x24, 0x04, 0x68, 0x00, 0x40, 0x03, 0x0c, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71
+ };
+
+ memcpy(&txid, recv_pkt, sizeof(txid));
+
+ node = NULL;
+ assert(!gwdns_parse_query(txid, "80", recv_pkt, sizeof(recv_pkt), &d));
+ assert(d);
+ node = d;
+ while (node) {
+ struct gwdns_addrinfo_node *tmp;
+ char buff[FULL_ADDRSTRLEN];
+
+ tmp = node->ai_next;
+ assert(node->ai_family == AF_INET6);
+ convert_ssaddr_to_str(buff, &node->ai_addr);
+ printf("IPv6: %s\n", buff);
+ node = tmp;
+ }
+
+ gwdns_free_parsed_query(d);
+}
+
+void test_build_ipv4(void)
+{
+ uint8_t buff[UDP_MSG_LIMIT];
+ gwdns_header_pkt *hdr;
+ uint16_t c;
+ ssize_t r;
+
+ c = 0xFFFF;
+ r = gwdns_build_query(c, "google.com", AF_INET, buff, sizeof(buff));
+ assert(r > 0);
+
+ hdr = (void *)buff;
+ assert(ntohs(hdr->qdcount) == 1);
+ assert(!hdr->nscount);
+ assert(!DNS_QR(hdr->flags));
+ assert(DNS_OPCODE(hdr->flags) == OPCODE_QUERY);
+ c = htons(TYPE_A);
+ assert(!memcmp(buff + 12 + 12, &c, 2));
+}
+
+void test_build_ipv6(void)
+{
+ uint8_t buff[UDP_MSG_LIMIT];
+ gwdns_header_pkt *hdr;
+ uint16_t c;
+ ssize_t r;
+
+ c = 0xFFFF;
+ r = gwdns_build_query(c, "google.com", AF_INET6, buff, sizeof(buff));
+ assert(r > 0);
+
+ hdr = (void *)buff;
+ assert(ntohs(hdr->qdcount) == 1);
+ assert(!hdr->nscount);
+ assert(!DNS_QR(hdr->flags));
+ assert(DNS_OPCODE(hdr->flags) == OPCODE_QUERY);
+ c = htons(TYPE_AAAA);
+ assert(!memcmp(buff + 12 + 12, &c, 2));
+}
+
+/*
+ * test mock data of recv in both IPv4 and IPv6
+ *
+ * the mock data are produced by this script:
+ * https://gist.github.com/realyukii/d7b450b4ddc305c66a2d8cd5600f23c4
+ */
+void run_all_tests(void)
+{
+ /*
+ * We can't use serialize_answ to parse multiple response at once.
+ * The caller MUST call serialize_answ more than one time if there's
+ * more than one response, because txid is passed to only verify one
+ * response.
+ */
+ fprintf(stderr, "test constructing DNS standard query packet for TYPE_A!\n");
+ test_build_ipv4();
+ fprintf(stderr, "test constructing DNS standard query packet for TYPE_AAAA!\n");
+ test_build_ipv6();
+ fprintf(stderr, "test parsing DNS standard query packet for TYPE_A!\n");
+ test_parse_ipv4();
+ fprintf(stderr, "test parsing DNS standard query packet for TYPE_AAAA!\n");
+ test_parse_ipv6();
+ fprintf(stderr, "all tests passed!\n");
+}
+
+int main(void)
+{
+ run_all_tests();
+ return 0;
+}
+
+#endif
diff --git a/src/gwproxy/dnsparser.h b/src/gwproxy/dnsparser.h
new file mode 100644
index 000000000000..6d5769cc3259
--- /dev/null
+++ b/src/gwproxy/dnsparser.h
@@ -0,0 +1,192 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <gwproxy/net.h>
+
+#ifndef GWP_DNS_PARSER_H
+#define GWP_DNS_PARSER_H
+
+#ifndef __packed
+#define __packed __attribute__((__packed__))
+#endif
+
+/*
+ * 4. MESSAGES
+ * 4.1. Format
+ *
+ * All communications inside of the domain protocol are carried in a single
+ * format called a message. The top-level format of a message is divided
+ * into 5 sections (some of which may be empty in certain cases), shown below:
+ *
+ * +---------------------+
+ * | Header |
+ * +---------------------+
+ * | Question | the question for the name server
+ * +---------------------+
+ * | Answer | RRs answering the question
+ * +---------------------+
+ * | Authority | RRs pointing toward an authority
+ * +---------------------+
+ * | Additional | RRs holding additional information
+ * +---------------------+
+ *
+ * These sections are defined in RFC 1035 §4.1. The Header section is always
+ * present and includes fields that specify which of the other sections follow,
+ * as well as metadata such as whether the message is a query or response,
+ * the opcode, etc.
+ */
+
+/* Flag bit position in little-endian machine */
+#define DNS_QR_BIT 0xF
+#define DNS_OPCODE_BIT 0xB // 4-bit field
+#define DNS_AA_BIT 0xA
+#define DNS_TC_BIT 0x9
+#define DNS_RD_BIT 0x8
+#define DNS_RA_BIT 0x7
+#define DNS_Z_BIT 0x4 // 3-bit field
+#define DNS_RCODE_BIT 0x0 // 4-bit field
+#define DNS_COMPRESSION_BIT (0x3 << 0xE)
+
+/* Flag extraction macros for listtle-endian machine */
+#define DNS_QR(flags) (((flags) >> DNS_QR_BIT) & 0x1)
+#define DNS_OPCODE(flags) (((flags) >> DNS_OPCODE_BIT) & 0xF)
+#define DNS_RCODE(flags) ((flags) & 0xF)
+#define DNS_IS_COMPRESSED(mask) ((mask) & DNS_COMPRESSION_BIT)
+
+/* Flag construction macros for little-endian machine */
+#define DNS_SET_RD(flags, val) (flags) = ((flags) & ~(1 << DNS_RD_BIT)) | ((!!(val)) << DNS_RD_BIT)
+
+/* as per RFC 1035 §2.3.4. Size limits */
+#define DOMAIN_LABEL_LIMIT 63
+#define DOMAIN_NAME_LIMIT 255
+#define UDP_MSG_LIMIT 512
+
+typedef enum {
+ OPCODE_QUERY = 0, // Standard query (QUERY)
+} gwdns_op;
+
+typedef enum {
+ TYPE_A = 1, // IPv4 host address
+ TYPE_CNAME = 5, // the canonical name for an alias
+ TYPE_AAAA = 28, // IPv6 host address
+} gwdns_type;
+
+typedef enum {
+ CLASS_IN = 1, // Internet
+} gwdns_class;
+
+typedef struct {
+ uint16_t id;
+ uint16_t flags;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+} __packed gwdns_header_pkt;
+
+typedef struct {
+ uint8_t question[UDP_MSG_LIMIT];
+ char answr[UDP_MSG_LIMIT];
+} gwdns_question_buffer;
+
+typedef struct {
+ uint8_t *dst_buffer;
+ uint16_t txid;
+ uint16_t type;
+ size_t dst_len;
+ const char *domain;
+} gwdns_question_part;
+
+/*
+ * 4.1.3. Resource record format
+ *
+ * The answer, authority, and additional sections all share the same
+ * format: a variable number of resource records, where the number of
+ * records is specified in the corresponding count field in the header.
+ */
+typedef struct {
+ uint8_t *name; // DOMAIN NAME: variable‑length sequence of labels (length-byte followed by label, ending in 0), possibly compressed
+ uint16_t rr_type; // TYPE: two-octet code identifying the RR type (see gwdns_type)
+ uint16_t rr_class; // CLASS: two-octet code identifying the RR class (see gwdns_class)
+ uint32_t ttl; // TTL: 32-bit unsigned, time to live in seconds
+ uint16_t rdlength; // RDLENGTH: length in octets of RDATA
+ uint8_t *rdata; // RDATA: variable-length data, format depends on TYPE and CLASS
+} gwdns_serialized_rr;
+
+typedef struct {
+ char qname[DOMAIN_NAME_LIMIT];
+ uint16_t qtype;
+ uint16_t qclass;
+} gwdns_serialized_question;
+
+typedef gwdns_serialized_rr gwdns_serialized_answ;
+
+typedef struct {
+ gwdns_header_pkt hdr;
+ uint8_t body[UDP_MSG_LIMIT];
+} gwdns_query_pkt;
+
+typedef struct {
+ gwdns_header_pkt hdr;
+ gwdns_serialized_question question;
+ gwdns_serialized_answ **rr_answ;
+} gwdns_answ_data;
+
+struct gwdns_addrinfo_node {
+ int ai_family;
+ int ai_ttl;
+ socklen_t ai_addrlen;
+ struct gwp_sockaddr ai_addr;
+ struct gwdns_addrinfo_node *ai_next;
+};
+
+/*
+ * Build standard query for domain name lookup.
+ *
+ * The caller may need to check for potential transaction ID collisions.
+ *
+ * Possible errors are:
+ * - ENAMETOOLONG name is too long.
+ * - ENOBUFS length specified by out_len is not sufficient.
+ * - EINVAL malformed name or unsupported value of family.
+ *
+ * @param txid transaction id
+ * @param name domain name
+ * @param family choose request for IPv4 or IPv6
+ * @param out destination buffer for constructed packet
+ * @param out_len available capacity of destination buffer
+ * @return length of bytes written into dst_buffer on success,
+ * or a negative integer on failure.
+ */
+ssize_t gwdns_build_query(uint16_t txid, const char *name, int family, uint8_t *out, size_t out_len);
+
+/*
+ * Parse name server's answer
+ *
+ * Possible errors are:
+ * -EAGAIN in buffer is not sufficient, no bytes are processed, need more data.
+ * -EINVAL the content of in buffer is not valid.
+ * -ENOMEM failed to allocate dynamic memory.
+ * -ENODATA the packet didn't contain any answers.
+ * -EPROTO the DNS server can't understand your question
+ *
+ * @param txid transaction id of question
+ * @param service port number in ascii
+ * @param in a pointer to buffer that need to be parsed
+ * @param in_len a pointer to buffer that need to be parsed
+ * @param ai a pointer to address info
+ * @return zero on success or a negative number on failure
+ */
+int gwdns_parse_query(uint16_t txid, const char *service,
+ uint8_t *in, size_t in_len,
+ struct gwdns_addrinfo_node **ai);
+void gwdns_free_parsed_query(struct gwdns_addrinfo_node *addrinfo);
+
+#endif /* #ifndef GWP_DNS_PARSER_H */
--
Ahmad Gani
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH gwproxy v11 4/6] gwproxy: Refactor code base to add experimental raw DNS backend
2025-09-14 5:09 [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ahmad Gani
` (2 preceding siblings ...)
2025-09-14 5:09 ` [PATCH gwproxy v11 3/6] dnsparser: Add dns parser code Ahmad Gani
@ 2025-09-14 5:09 ` Ahmad Gani
2025-09-14 12:14 ` Ammar Faizi
2025-09-14 5:09 ` [PATCH gwproxy v11 5/6] gwproxy: Update Makefile and configure scripts Ahmad Gani
` (3 subsequent siblings)
7 siblings, 1 reply; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 5:09 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Ahmad Gani, Alviro Iskandar Setiawan, GNU/Weeb Mailing List
The raw DNS backend is 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.
When experimental raw DNS is enabled in gwproxy, the program benefits from:
- disabling DNS worker threads
- disabling eventfd that used to communicate between threads
- disabling condition variables and mutex locks
- disabling reference counting (no need to prevent UAF)
Use 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 if it failed.
Add new cmdline arguments:
- raw-dns: enables the experimental raw DNS feature
- dns-server: sets the default DNS server
- session-map-cap: sets the default capacity for the session_map and stack.arr arrays
The struct gwp_dns_ctx is now exported due to the need for accessing it
outside dns.c.
Signed-off-by: Ahmad Gani <reyuki@gnuweeb.org>
---
src/gwproxy/dns.c | 269 ++++++++++++++++++++++++++++++++++-------
src/gwproxy/dns.h | 57 ++++++++-
src/gwproxy/ev/epoll.c | 142 ++++++++++++++++++++--
src/gwproxy/gwproxy.c | 199 +++++++++++++++++++++++++++++-
src/gwproxy/gwproxy.h | 88 ++++++++++++++
5 files changed, 688 insertions(+), 67 deletions(-)
diff --git a/src/gwproxy/dns.c b/src/gwproxy/dns.c
index bd8c90fb1449..c881b034611f 100644
--- a/src/gwproxy/dns.c
+++ b/src/gwproxy/dns.c
@@ -23,8 +23,7 @@
#include <pthread.h>
#include <sys/eventfd.h>
-
-struct gwp_dns_ctx;
+#include <gwproxy/dnsparser.h>
struct gwp_dns_wrk {
struct gwp_dns_ctx *ctx;
@@ -32,20 +31,6 @@ struct gwp_dns_wrk {
pthread_t thread;
};
-struct gwp_dns_ctx {
- volatile bool should_stop;
- pthread_mutex_t lock;
- pthread_cond_t cond;
- uint32_t nr_sleeping;
- uint32_t nr_entries;
- struct gwp_dns_entry *head;
- struct gwp_dns_entry *tail;
- struct gwp_dns_wrk *workers;
- struct gwp_dns_cache *cache;
- time_t last_scan;
- struct gwp_dns_cfg cfg;
-};
-
static void put_all_entries(struct gwp_dns_entry *head)
{
struct gwp_dns_entry *e, *next;
@@ -182,6 +167,174 @@ int gwp_dns_resolve(struct gwp_dns_ctx *ctx, const char *name,
return found ? 0 : -EHOSTUNREACH;
}
+#ifdef CONFIG_RAW_DNS
+
+static void _gwp_dns_entry_free(struct gwp_dns_entry *e)
+{
+ assert(e);
+ 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;
+}
+
+static int attempt_fallback(struct gwp_dns_ctx *ctx, struct gwp_dns_entry *e)
+{
+ int af, r;
+
+ /* 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:
+ assert(0);
+ return -EINVAL;
+ }
+
+ r = (int)gwdns_build_query(e->txid,
+ e->name, af, e->payload, sizeof(e->payload));
+ if (r > 0) {
+ e->payloadlen = r;
+ r = -EAGAIN;
+ }
+
+ return r;
+}
+
+int gwp_dns_process(uint8_t buff[UDP_MSG_LIMIT], int bufflen, struct gwp_dns_ctx *ctx, struct gwp_dns_entry *e)
+{
+ struct gwdns_addrinfo_node *ai;
+ ssize_t r;
+
+ r = gwdns_parse_query(e->txid, e->service, buff, bufflen, &ai);
+ if (r) {
+ if (r == -ENODATA)
+ r = attempt_fallback(ctx, e);
+ goto exit;
+ }
+
+ e->addr = ai->ai_addr;
+
+ gwdns_free_parsed_query(ai);
+exit:
+ return (int)r;
+}
+
+struct gwp_dns_entry *gwp_raw_dns_queue(uint16_t txid, struct gwp_dns_ctx *ctx,
+ const char *name, const char *service)
+{
+ struct gwp_dns_entry *e;
+ size_t nl, sl;
+ ssize_t r;
+ int af;
+
+ e = malloc(sizeof(*e));
+ if (!e)
+ return NULL;
+
+ if (ctx->nr_entries == ctx->entry_cap && realloc_entries(ctx))
+ return NULL;
+
+ switch (ctx->cfg.restyp) {
+ case GWP_DNS_RESTYP_PREFER_IPV4:
+ case GWP_DNS_RESTYP_IPV4_ONLY:
+ case GWP_DNS_RESTYP_DEFAULT:
+ 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_free_e;
+ }
+
+ r = gwdns_build_query(txid,
+ name, af, e->payload, sizeof(e->payload));
+ if (r < 0)
+ goto out_free_e;
+ e->payloadlen = (int)r;
+
+ /*
+ * Merge name and service into a single allocated string to
+ * avoid multiple allocations.
+ *
+ * The format is: "<name>\0<service>\0" where both name and
+ * service are null-terminated strings.
+ */
+ nl = strlen(name);
+ sl = service ? strlen(service) : 0;
+ e->name = malloc(nl + 1 + sl + 1);
+ if (!e->name)
+ goto out_free_e;
+
+ e->service = e->name + nl + 1;
+ memcpy(e->name, name, nl + 1);
+ if (service)
+ memcpy(e->service, service, sl + 1);
+ else
+ e->service[0] = '\0';
+
+ e->res = 0;
+ e->idx = ctx->nr_entries++;
+ ctx->entries[e->idx] = e;
+
+ return e;
+out_free_e:
+ free(e);
+ return NULL;
+}
+#else
+static void free_all_queued_entries(__maybe_unused struct gwp_dns_ctx *ctx)
+{
+}
+#endif /* #ifdef CONFIG_RAW_DNS */
+
static void gwp_dns_entry_free(struct gwp_dns_entry *e)
{
if (!e)
@@ -713,39 +866,57 @@ int gwp_dns_ctx_init(struct gwp_dns_ctx **ctx_p, const struct gwp_dns_cfg *cfg)
return -ENOMEM;
ctx->cfg = *cfg;
- r = pthread_mutex_init(&ctx->lock, NULL);
- if (r) {
- r = -r;
- goto out_free_ctx;
- }
- r = pthread_cond_init(&ctx->cond, NULL);
- if (r) {
- r = -r;
- goto out_destroy_mutex;
- }
+ 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_free_ctx;
+ 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) {
+ __sys_close(r);
+ r = -ENOMEM;
+ goto out_free_ctx;
+ }
+#endif
+ } else {
+ r = pthread_mutex_init(&ctx->lock, NULL);
+ if (r) {
+ r = -r;
+ goto out_free_ctx;
+ }
- r = init_cache(ctx);
- if (r)
- goto out_destroy_cond;
+ r = pthread_cond_init(&ctx->cond, NULL);
+ if (r) {
+ r = -r;
+ goto out_destroy_mutex;
+ }
- 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->nr_sleeping = 0;
+ ctx->workers = NULL;
+ ctx->head = NULL;
+ ctx->tail = NULL;
+ r = init_workers(ctx);
+ if (r)
+ goto out_destroy_cond;
+ r = init_cache(ctx);
+ if (r)
+ goto out_destroy_cond;
+
+ ctx->should_stop = false;
+ ctx->last_scan = time(NULL);
+ }
+ ctx->nr_entries = 0;
*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,11 +933,15 @@ static void put_all_queued_entries(struct gwp_dns_ctx *ctx)
void gwp_dns_ctx_free(struct gwp_dns_ctx *ctx)
{
- free_workers(ctx);
- pthread_mutex_destroy(&ctx->lock);
- pthread_cond_destroy(&ctx->cond);
- put_all_queued_entries(ctx);
- free_cache(ctx->cache);
+ if (ctx->cfg.use_raw_dns) {
+ free_all_queued_entries(ctx);
+ } else {
+ free_workers(ctx);
+ pthread_mutex_destroy(&ctx->lock);
+ pthread_cond_destroy(&ctx->cond);
+ put_all_queued_entries(ctx);
+ free_cache(ctx->cache);
+ }
free(ctx);
}
diff --git a/src/gwproxy/dns.h b/src/gwproxy/dns.h
index 420a80e5cf6a..049505997e37 100644
--- a/src/gwproxy/dns.h
+++ b/src/gwproxy/dns.h
@@ -9,12 +9,20 @@
#include <stdatomic.h>
#include <stdbool.h>
#include <netinet/in.h>
+#include <gwproxy/common.h>
#include <gwproxy/net.h>
+#include <gwproxy/dnsparser.h>
#include <gwproxy/syscall.h>
-struct gwp_dns_wrk;
-
struct gwp_dns_entry {
+#ifdef CONFIG_RAW_DNS
+ uint32_t idx;
+ int payloadlen;
+ union {
+ uint16_t txid;
+ uint8_t payload[UDP_MSG_LIMIT];
+ };
+#endif
char *name;
char *service;
_Atomic(int) refcnt;
@@ -32,13 +40,37 @@ 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;
+struct gwp_dns_ctx {
+#ifdef CONFIG_RAW_DNS
+ uint32_t entry_cap;
+ struct gwp_dns_entry **entries;
+ struct gwp_sockaddr ns_addr;
+ socklen_t ns_addrlen;
+#endif
+ volatile bool should_stop;
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ uint32_t nr_sleeping;
+ uint32_t nr_entries;
+ struct gwp_dns_entry *head;
+ struct gwp_dns_entry *tail;
+ struct gwp_dns_wrk *workers;
+ struct gwp_dns_cache *cache;
+ time_t last_scan;
+ struct gwp_dns_cfg cfg;
+};
/**
* Initialize the DNS context. Stores the context in `*ctx_p`. When
@@ -88,6 +120,25 @@ 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
+struct gwp_dns_entry *gwp_raw_dns_queue(uint16_t txid, struct gwp_dns_ctx *ctx,
+ const char *name, const char *service);
+
+void gwp_dns_raw_entry_free(struct gwp_dns_ctx *ctx, struct gwp_dns_entry *e);
+
+int gwp_dns_process(uint8_t buff[UDP_MSG_LIMIT], int bufflen, struct gwp_dns_ctx *ctx, struct gwp_dns_entry *e);
+#else
+static inline struct gwp_dns_entry *gwp_raw_dns_queue(__maybe_unused uint16_t txid, __maybe_unused struct gwp_dns_ctx *ctx,
+ __maybe_unused const char *name, __maybe_unused const char *service)
+{
+ return NULL;
+}
+
+static inline void gwp_dns_raw_entry_free(__maybe_unused struct gwp_dns_ctx *ctx, __maybe_unused 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..5926bb5e090a 100644
--- a/src/gwproxy/ev/epoll.c
+++ b/src/gwproxy/ev/epoll.c
@@ -39,6 +39,16 @@ int gwp_ctx_init_thread_epoll(struct gwp_wrk *w)
goto out_close_ep_fd;
}
+ if (w->ctx->cfg.use_raw_dns) {
+#ifdef CONFIG_RAW_DNS
+ ev.events = EPOLLIN;
+ ev.data.u64 = EV_BIT_DNS_QUERY;
+ r = __sys_epoll_ctl(ep_fd, EPOLL_CTL_ADD, w->dns_resolver.udp_fd, &ev);
+ if (unlikely(r))
+ return (int)r;
+#endif
+ }
+
w->evsz = 512;
events = calloc(w->evsz, sizeof(*events));
if (!events) {
@@ -778,6 +788,89 @@ static int handle_connect(struct gwp_wrk *w, struct gwp_conn_pair *gcp)
return 0;
}
+#ifdef CONFIG_RAW_DNS
+static int send_raw_dns_query(struct gwp_wrk *w, struct gwp_conn_pair *gcp)
+{
+ struct gwp_dns_entry *gde = gcp->gde;
+ struct gwp_dns_ctx *dctx;
+ ssize_t r;
+
+ dctx = w->ctx->dns;
+ r = __sys_sendto(
+ w->dns_resolver.udp_fd, gde->payload, gde->payloadlen, MSG_NOSIGNAL,
+ &dctx->ns_addr.sa, dctx->ns_addrlen
+ );
+ if (r < 0)
+ return (int)r;
+ pr_dbg(&w->ctx->lh, "standard DNS query for %s has been sent", gde->name);
+
+ return 0;
+}
+static int read_raw_dns_answer(struct gwp_wrk *w, struct gwp_conn_pair **pgcp,
+ struct gwp_dns_entry **pgde)
+{
+ uint8_t buff[UDP_MSG_LIMIT];
+ struct gwp_conn_pair *gcp;
+ struct gwp_dns_entry *gde;
+ struct gwp_dns_ctx *dctx;
+ uint16_t txid;
+ int r;
+
+ dctx = w->ctx->dns;
+ r = (int)__sys_recvfrom(
+ w->dns_resolver.udp_fd, buff, sizeof(buff), 0,
+ &dctx->ns_addr.sa, &dctx->ns_addrlen
+ );
+ if (r < 0)
+ return (int)r;
+ if (r < 38)
+ return -EINVAL;
+
+ memcpy(&txid, buff, 2);
+ if (txid >= w->dns_resolver.sess_map_cap) {
+ pr_err(&w->ctx->lh, "txid is bigger than sess_map_cap: %hu\n", txid);
+ return -EINVAL;
+ }
+
+ gcp = w->dns_resolver.sess_map[txid];
+ if (!gcp)
+ return -ENOENT;
+
+ gde = gcp->gde;
+ pr_dbg(&w->ctx->lh, "proxy session for DNS query %s was found!", gde->name);
+ r = gwp_dns_process(buff, r, dctx, gde);
+ if (r == -EAGAIN) {
+ pr_dbg(&w->ctx->lh, "DNS Fallback");
+ r = send_raw_dns_query(w, gcp);
+ if (r)
+ return r;
+
+ return -EAGAIN;
+ } else if (r)
+ gde->res = r;
+
+ r = return_txid(w, gde);
+ assert(!r);
+ if (r)
+ return r;
+
+ *pgcp = gcp;
+ *pgde = gde;
+ return 0;
+}
+#else
+static int send_raw_dns_query(__maybe_unused struct gwp_wrk *w, __maybe_unused struct gwp_conn_pair *gcp)
+{
+ return 0;
+}
+static int read_raw_dns_answer(__maybe_unused struct gwp_wrk *w,
+ __maybe_unused struct gwp_conn_pair **pgcp,
+ __maybe_unused struct gwp_dns_entry **pgde)
+{
+ return 0;
+}
+#endif
+
static int arm_poll_for_dns_query(struct gwp_wrk *w,
struct gwp_conn_pair *gcp)
{
@@ -786,16 +879,22 @@ static int arm_poll_for_dns_query(struct gwp_wrk *w,
int 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 (unlikely(r))
- return r;
+ if (w->ctx->cfg.use_raw_dns) {
+ r = send_raw_dns_query(w, gcp);
+ if (r)
+ return r;
+ } else {
+ assert(gde->ev_fd >= 0);
+ r = __sys_epoll_ctl(w->ep_fd, EPOLL_CTL_ADD, gde->ev_fd, &ev);
+ if (unlikely(r))
+ return r;
+ }
return 0;
}
@@ -822,18 +921,30 @@ static void log_dns_query(struct gwp_wrk *w, struct gwp_conn_pair *gcp,
__hot
static int handle_ev_dns_query(struct gwp_wrk *w, struct gwp_conn_pair *gcp)
{
- struct gwp_dns_entry *gde = gcp->gde;
- int r, ct = gcp->conn_state;
+ struct gwp_dns_entry *gde = NULL;
+ int r, ct;
- assert(gde);
- assert(gde->ev_fd >= 0);
+ if (w->ctx->cfg.use_raw_dns) {
+ r = read_raw_dns_answer(w, &gcp, &gde);
+ if (r) {
+ if (r == -EAGAIN)
+ return 0;
+ else
+ return r;
+ }
+ } else {
+ gde = gcp->gde;
+ assert(gde);
+ assert(gde->ev_fd >= 0);
+ r = __sys_epoll_ctl(w->ep_fd, EPOLL_CTL_DEL, gde->ev_fd, NULL);
+ if (unlikely(r))
+ return r;
+ }
+
+ ct = gcp->conn_state;
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;
-
log_dns_query(w, gcp, gde);
if (likely(!gde->res)) {
gcp->target_addr = gde->addr;
@@ -845,7 +956,12 @@ 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) {
+ pr_dbg(&w->ctx->lh, "removing proxy session from the %s's txid map", gde->name);
+ gwp_dns_raw_entry_free(w->ctx->dns, gde);
+ } else {
+ gwp_dns_entry_put(gde);
+ }
gcp->gde = NULL;
return r;
}
diff --git a/src/gwproxy/gwproxy.c b/src/gwproxy/gwproxy.c
index 3d277f7ee6f8..e14780f23945 100644
--- a/src/gwproxy/gwproxy.c
+++ b/src/gwproxy/gwproxy.c
@@ -44,6 +44,11 @@
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' },
+ { "session-map-cap", required_argument, NULL, 's' },
+#endif
{ "event-loop", required_argument, NULL, 'e' },
{ "bind", required_argument, NULL, 'b' },
{ "target", required_argument, NULL, 't' },
@@ -74,6 +79,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,
@@ -94,6 +100,10 @@ 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",
+ .sess_map_cap = 16
+#endif
};
__cold
@@ -104,6 +114,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);
@@ -159,6 +173,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;
@@ -228,6 +245,14 @@ 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;
+ case 's':
+ cfg->sess_map_cap = atoi(optarg);
+ break;
+#endif
default:
fprintf(stderr, "Unknown option: %c\n", c);
show_help(argv[0]);
@@ -446,6 +471,136 @@ static void gwp_ctx_free_thread_event(struct gwp_wrk *w)
}
}
+#ifdef CONFIG_RAW_DNS
+static inline int realloc_stack(struct dns_resolver *resolv)
+{
+ struct gwp_conn_pair **cp;
+ size_t newcap, oldcap;
+ uint16_t *stack;
+ uint16_t j, idx;
+
+ oldcap = resolv->sess_map_cap;
+ newcap = oldcap * 2;
+ if (newcap > 65536)
+ return -ENOSPC;
+
+ cp = realloc(resolv->sess_map, sizeof(*cp) * newcap);
+ if (!cp)
+ return -ENOMEM;
+
+ resolv->sess_map = cp;
+ resolv->sess_map_cap = newcap;
+ memset(&resolv->sess_map[oldcap], 0, oldcap);
+
+ stack = realloc(resolv->stack.arr, sizeof(*stack) * newcap);
+ if (!stack)
+ return -ENOMEM;
+ resolv->stack.arr = stack;
+ resolv->stack.top = newcap;
+
+ j = (uint16_t)newcap - 1;
+ for (idx = 0; j > resolv->stack.top; idx++,j--)
+ stack[idx] = j;
+
+ return 0;
+}
+
+static inline int pop_txid(struct dns_resolver *resolv)
+{
+ int r;
+ if (resolv->stack.top == 0) {
+ r = realloc_stack(resolv);
+ if (r)
+ return -EAGAIN;
+ }
+
+ return resolv->stack.arr[--resolv->stack.top];
+}
+
+static struct gwp_dns_entry *generate_gde(struct gwp_wrk *w, struct gwp_conn_pair *gcp, const char *host, const char *port)
+{
+ struct gwp_dns_entry *gde;
+ struct gwp_dns_ctx *dns = w->ctx->dns;
+ int txid;
+
+ txid = pop_txid(&w->dns_resolver);
+ if (txid < 0)
+ return NULL;
+
+ gde = gwp_raw_dns_queue((uint16_t)txid, dns, host, port);
+ if (!gde) {
+ return_txid(w, gde);
+ return NULL;
+ }
+ pr_dbg(&w->ctx->lh, "constructing standard DNS query packet for %s", host);
+ w->dns_resolver.sess_map[txid] = gcp;
+
+ return gde;
+}
+
+static int gwp_ctx_init_dns_resolver(struct gwp_wrk *w)
+{
+ struct dns_resolver *resolv;
+ struct gwp_dns_ctx *dns;
+ struct gwp_cfg *cfg;
+ struct gwp_ctx *ctx;
+ int udp_fd, r;
+ void *ptr;
+
+ ctx = w->ctx;
+ cfg = &ctx->cfg;
+ dns = ctx->dns;
+ udp_fd = __sys_socket(dns->ns_addr.sa.sa_family, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+ if (udp_fd < 0) {
+ pr_err(&w->ctx->lh, "Failed to create udp_fd: %s\n", strerror(-udp_fd));
+ return udp_fd;
+ }
+
+ resolv = &w->dns_resolver;
+ resolv->sess_map = NULL;
+ resolv->stack.arr = NULL;
+ r = reset_stack(w);
+ if (r) {
+ if (resolv->stack.arr)
+ free(resolv->stack.arr);
+ if (resolv->sess_map)
+ free(resolv->sess_map);
+ __sys_close(udp_fd);
+
+ return r;
+ }
+
+ memset(resolv->sess_map, 0, cfg->sess_map_cap * sizeof(ptr));
+ resolv->udp_fd = udp_fd;
+
+ return 0;
+}
+
+static void gwp_ctx_free_raw_dns(struct gwp_wrk *w)
+{
+ struct dns_resolver *resolv = &w->dns_resolver;
+ __sys_close(resolv->udp_fd);
+ free(resolv->sess_map);
+ free(resolv->stack.arr);
+}
+#else
+static struct gwp_dns_entry *generate_gde(__maybe_unused struct gwp_wrk *w,
+ __maybe_unused struct gwp_conn_pair *gcp,
+ __maybe_unused const char *host,
+ __maybe_unused const char *port)
+{
+ return NULL;
+}
+static int gwp_ctx_init_dns_resolver(__maybe_unused struct gwp_wrk *w)
+{
+ return 0;
+}
+
+static void gwp_ctx_free_raw_dns(__maybe_unused struct gwp_wrk *w)
+{
+}
+#endif /* #ifdef CONFIG_RAW_DNS */
+
__cold
static int gwp_ctx_init_thread(struct gwp_wrk *w,
const struct gwp_sockaddr *bind_addr)
@@ -459,6 +614,14 @@ static int gwp_ctx_init_thread(struct gwp_wrk *w,
return r;
}
+ if (ctx->cfg.use_raw_dns) {
+ r = gwp_ctx_init_dns_resolver(w);
+ if (r) {
+ pr_err(&ctx->lh, "gwp_ctx_init_thread_event: %s\n", strerror(-r));
+ gwp_ctx_free_thread_sock(w);
+ }
+ }
+
r = gwp_ctx_init_thread_event(w);
if (r < 0) {
pr_err(&ctx->lh, "gwp_ctx_init_thread_event: %s\n", strerror(-r));
@@ -529,6 +692,8 @@ static void gwp_ctx_signal_all_workers(struct gwp_ctx *ctx)
__cold
static void gwp_ctx_free_thread(struct gwp_wrk *w)
{
+ if (w->ctx->cfg.use_raw_dns)
+ gwp_ctx_free_raw_dns(w);
gwp_ctx_free_thread_sock_pairs(w);
gwp_ctx_free_thread_sock(w);
gwp_ctx_free_thread_event(w);
@@ -689,12 +854,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 = cfg->nr_dns_workers,
+#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 +909,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 +1170,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) {
+ pr_dbg(&w->ctx->lh, "client disconnected before query for %s resolved", gcp->gde->name);
+ if (w->ctx->cfg.use_raw_dns) {
+ return_txid(w, gcp->gde);
+ gwp_dns_raw_entry_free(w->ctx->dns, gcp->gde);
+ } else {
+ gwp_dns_entry_put(gcp->gde);
+ }
+ }
switch (gcp->prot_type) {
case GWP_PROT_TYPE_SOCKS5:
@@ -1192,7 +1379,11 @@ static int queue_dns_resolution(struct gwp_wrk *w, struct gwp_conn_pair *gcp,
struct gwp_dns_ctx *dns = w->ctx->dns;
struct gwp_dns_entry *gde;
- gde = gwp_dns_queue(dns, host, port);
+ if (w->ctx->cfg.use_raw_dns)
+ gde = generate_gde(w, gcp, host, port);
+ else
+ gde = gwp_dns_queue(dns, host, port);
+
if (unlikely(!gde)) {
pr_err(&w->ctx->lh, "Failed to allocate DNS entry for %s:%s", host, port);
return -ENOMEM;
diff --git a/src/gwproxy/gwproxy.h b/src/gwproxy/gwproxy.h
index 095c0ce700c3..9930934b893e 100644
--- a/src/gwproxy/gwproxy.h
+++ b/src/gwproxy/gwproxy.h
@@ -9,6 +9,7 @@
#define _GNU_SOURCE
#endif
+#include <gwproxy/common.h>
#include <gwproxy/syscall.h>
#include <gwproxy/socks5.h>
#include <gwproxy/dns.h>
@@ -24,6 +25,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;
@@ -44,6 +46,10 @@ struct gwp_cfg {
int log_level;
const char *log_file;
const char *pid_file;
+#ifdef CONFIG_RAW_DNS
+ const char *ns_addr_str;
+ int sess_map_cap;
+#endif
};
struct gwp_ctx;
@@ -195,8 +201,24 @@ struct iou {
};
#endif
+struct stack_u16 {
+ uint16_t top;
+ uint16_t *arr;
+};
+
+struct dns_resolver {
+ struct stack_u16 stack;
+ struct gwp_conn_pair **sess_map;
+ uint16_t sess_map_cap;
+ int udp_fd;
+};
+
struct gwp_wrk {
int tcp_fd;
+#ifdef CONFIG_RAW_DNS
+ /* For mapping DNS queries to the corresponding proxy session */
+ struct dns_resolver dns_resolver;
+#endif
struct gwp_conn_slot conn_slot;
union {
@@ -251,6 +273,72 @@ int gwp_create_timer(int fd, int sec, int nsec);
void gwp_setup_cli_sock_options(struct gwp_wrk *w, int fd);
const char *ip_to_str(const struct gwp_sockaddr *gs);
+#ifdef CONFIG_RAW_DNS
+static inline int reset_stack(struct gwp_wrk *w)
+{
+ struct dns_resolver *resolv;
+ struct gwp_cfg *cfg;
+ uint16_t *p1;
+ int i, d;
+ void *p2;
+
+ cfg = &w->ctx->cfg;
+ d = cfg->sess_map_cap;
+ resolv = &w->dns_resolver;
+ p1 = realloc(resolv->stack.arr, d * sizeof(*resolv->stack.arr));
+ if (!p1)
+ return -ENOMEM;
+ resolv->stack.arr = p1;
+ resolv->stack.top = d;
+
+ i = d;
+ resolv->stack.top = i--;
+ for (; i >= 0; i--)
+ p1[i] = i;
+
+ p2 = realloc(resolv->sess_map, d * sizeof(*resolv->sess_map));
+ if (!p2)
+ return -ENOMEM;
+ resolv->sess_map = p2;
+ memset(p2, 0, d * sizeof(*resolv->sess_map));
+ resolv->sess_map_cap = d;
+
+ return 0;
+}
+
+static inline int return_txid(struct gwp_wrk *w, struct gwp_dns_entry *gde)
+{
+ struct dns_resolver *resolv;
+ struct gwp_cfg *cfg;
+ uint16_t idx;
+
+ resolv = &w->dns_resolver;
+ cfg = &w->ctx->cfg;
+ /* the program shouldn't return more than its pop */
+ if (resolv->stack.top >= resolv->sess_map_cap) {
+ assert(0);
+ return -EINVAL;
+ }
+
+ idx = resolv->stack.top++;
+ resolv->stack.arr[idx] = gde->txid;
+ resolv->sess_map[idx] = NULL;
+ /* shrinks it when there is no active query
+ * and the allocated size is larger than the default size.
+ */
+ if (idx == resolv->sess_map_cap &&
+ resolv->sess_map_cap > cfg->sess_map_cap)
+ reset_stack(w);
+
+ return 0;
+}
+#else
+static inline int return_txid(__maybe_unused struct gwp_wrk *w, __maybe_unused struct gwp_dns_entry *gde)
+{
+ return 0;
+}
+#endif
+
static inline void gwp_conn_buf_advance(struct gwp_conn *conn, size_t len)
{
assert(len <= conn->len);
--
Ahmad Gani
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH gwproxy v11 4/6] gwproxy: Refactor code base to add experimental raw DNS backend
2025-09-14 5:09 ` [PATCH gwproxy v11 4/6] gwproxy: Refactor code base to add experimental raw DNS backend Ahmad Gani
@ 2025-09-14 12:14 ` Ammar Faizi
2025-09-14 13:54 ` Alviro Iskandar Setiawan
2025-09-14 17:46 ` Ahmad Gani
0 siblings, 2 replies; 24+ messages in thread
From: Ammar Faizi @ 2025-09-14 12:14 UTC (permalink / raw)
To: Ahmad Gani; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 12:09:38PM +0700, Ahmad Gani wrote:
> Use 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 if it failed.
>
> Add new cmdline arguments:
> - raw-dns: enables the experimental raw DNS feature
> - dns-server: sets the default DNS server
> - session-map-cap: sets the default capacity for the session_map and stack.arr arrays
>
> The struct gwp_dns_ctx is now exported due to the need for accessing it
> outside dns.c.
Let me tell you this again. Please ponder it seriously!
Take a break. Use your brain to actually comprehend the meaning.
Each patch should only do one substantial thing. And if **you refactor**
something, **do it independently** with your feature addition. Don't mix
them into a single patch.
"Feature addition" **is not** a part of code refactoring. If you
refactor something, there must not be a functional change.
"Code refactoring" MUST NOT add a new feature.
--
Ammar Faizi
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 4/6] gwproxy: Refactor code base to add experimental raw DNS backend
2025-09-14 12:14 ` Ammar Faizi
@ 2025-09-14 13:54 ` Alviro Iskandar Setiawan
2025-09-14 17:46 ` Ahmad Gani
1 sibling, 0 replies; 24+ messages in thread
From: Alviro Iskandar Setiawan @ 2025-09-14 13:54 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Ahmad Gani, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 7:14 PM Ammar Faizi wrote:
> "Code refactoring" MUST NOT add a new feature.
That's right. Google "code refactoring meaning":
"Code refactoring is the process of restructuring existing source
code without changing its external functionality to improve its
internal structure, readability, and maintainability"
Ahmad Gani clearly doesn't understand what code refactoring means.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 4/6] gwproxy: Refactor code base to add experimental raw DNS backend
2025-09-14 12:14 ` Ammar Faizi
2025-09-14 13:54 ` Alviro Iskandar Setiawan
@ 2025-09-14 17:46 ` Ahmad Gani
1 sibling, 0 replies; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 17:46 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 7:14 PM Ammar Faizi wrote:
> On Sun, Sep 14, 2025 at 12:09:38PM +0700, Ahmad Gani wrote:
> > Use 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 if it failed.
> >
> > Add new cmdline arguments:
> > - raw-dns: enables the experimental raw DNS feature
> > - dns-server: sets the default DNS server
> > - session-map-cap: sets the default capacity for the session_map and stack.arr arrays
> >
> > The struct gwp_dns_ctx is now exported due to the need for accessing it
> > outside dns.c.
>
> Let me tell you this again. Please ponder it seriously!
>
> Take a break. Use your brain to actually comprehend the meaning.
>
> Each patch should only do one substantial thing. And if **you refactor**
> something, **do it independently** with your feature addition. Don't mix
> them into a single patch.
>
> "Feature addition" **is not** a part of code refactoring. If you
> refactor something, there must not be a functional change.
>
> "Code refactoring" MUST NOT add a new feature.
Do I just need to rename the subject to "Integrate new experimental raw
DNS backend to the code base"? splitting this patch seems not a good idea
since the overall changes represent one substantial thing.
--
Ahmad Gani
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH gwproxy v11 5/6] gwproxy: Update Makefile and configure scripts
2025-09-14 5:09 [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ahmad Gani
` (3 preceding siblings ...)
2025-09-14 5:09 ` [PATCH gwproxy v11 4/6] gwproxy: Refactor code base to add experimental raw DNS backend Ahmad Gani
@ 2025-09-14 5:09 ` Ahmad Gani
2025-09-14 12:55 ` Ammar Faizi
2025-09-14 5:09 ` [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS Ahmad Gani
` (2 subsequent siblings)
7 siblings, 1 reply; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 5:09 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Ahmad Gani, Alviro Iskandar Setiawan, GNU/Weeb Mailing List
Add an option to build experimental raw DNS feature.
Signed-off-by: Ahmad Gani <reyuki@gnuweeb.org>
---
Makefile | 2 +-
configure | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
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 44c49da20de4..1cc61e7691da 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_flag "-fsanitize=address"; then
--
Ahmad Gani
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH gwproxy v11 5/6] gwproxy: Update Makefile and configure scripts
2025-09-14 5:09 ` [PATCH gwproxy v11 5/6] gwproxy: Update Makefile and configure scripts Ahmad Gani
@ 2025-09-14 12:55 ` Ammar Faizi
2025-09-14 17:45 ` Ahmad Gani
0 siblings, 1 reply; 24+ messages in thread
From: Ammar Faizi @ 2025-09-14 12:55 UTC (permalink / raw)
To: Ahmad Gani; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 12:09:39PM +0700, Ahmad Gani wrote:
> Add an option to build experimental raw DNS feature.
Don't use "Update Makefile and configure scripts" as the subject. Every
patch you send DO update files, saying "Update file X" on the subject
is not very meaningful for git shortlog.
Your body content "Add an option to build experimental raw DNS feature"
is much a better subject than "Update this and that".
--
Ammar Faizi
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 5/6] gwproxy: Update Makefile and configure scripts
2025-09-14 12:55 ` Ammar Faizi
@ 2025-09-14 17:45 ` Ahmad Gani
0 siblings, 0 replies; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 17:45 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 7:55 PM Ammar Faizi wrote:
> On Sun, Sep 14, 2025 at 12:09:39PM +0700, Ahmad Gani wrote:
> > Add an option to build experimental raw DNS feature.
>
> Don't use "Update Makefile and configure scripts" as the subject. Every
> patch you send DO update files, saying "Update file X" on the subject
> is not very meaningful for git shortlog.
Oh, makes sense.
> Your body content "Add an option to build experimental raw DNS feature"
> is much a better subject than "Update this and that".
Ok, I will use body content as the commit subject.
--
Ahmad Gani
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 5:09 [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ahmad Gani
` (4 preceding siblings ...)
2025-09-14 5:09 ` [PATCH gwproxy v11 5/6] gwproxy: Update Makefile and configure scripts Ahmad Gani
@ 2025-09-14 5:09 ` Ahmad Gani
2025-09-14 12:16 ` Ammar Faizi
2025-09-14 12:51 ` (subset) [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ammar Faizi
2025-09-14 17:22 ` Alviro Iskandar Setiawan
7 siblings, 1 reply; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 5:09 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Ahmad Gani, Alviro Iskandar Setiawan, GNU/Weeb Mailing List
No need to wrap struct members in #ifdef, adding a couple of bytes isn't
a big deal.
Signed-off-by: Ahmad Gani <reyuki@gnuweeb.org>
---
src/gwproxy/dns.c | 2 --
src/gwproxy/dns.h | 8 +-------
src/gwproxy/ev/epoll.c | 4 +---
src/gwproxy/gwproxy.c | 10 ----------
src/gwproxy/gwproxy.h | 6 +-----
5 files changed, 3 insertions(+), 27 deletions(-)
diff --git a/src/gwproxy/dns.c b/src/gwproxy/dns.c
index c881b034611f..cd43c7c2f698 100644
--- a/src/gwproxy/dns.c
+++ b/src/gwproxy/dns.c
@@ -868,7 +868,6 @@ int gwp_dns_ctx_init(struct gwp_dns_ctx **ctx_p, const struct gwp_dns_cfg *cfg)
ctx->cfg = *cfg;
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_free_ctx;
@@ -882,7 +881,6 @@ int gwp_dns_ctx_init(struct gwp_dns_ctx **ctx_p, const struct gwp_dns_cfg *cfg)
r = -ENOMEM;
goto out_free_ctx;
}
-#endif
} else {
r = pthread_mutex_init(&ctx->lock, NULL);
if (r) {
diff --git a/src/gwproxy/dns.h b/src/gwproxy/dns.h
index 049505997e37..30658090f130 100644
--- a/src/gwproxy/dns.h
+++ b/src/gwproxy/dns.h
@@ -15,14 +15,12 @@
#include <gwproxy/syscall.h>
struct gwp_dns_entry {
-#ifdef CONFIG_RAW_DNS
uint32_t idx;
int payloadlen;
union {
uint16_t txid;
uint8_t payload[UDP_MSG_LIMIT];
};
-#endif
char *name;
char *service;
_Atomic(int) refcnt;
@@ -47,18 +45,14 @@ struct gwp_dns_cfg {
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 {
-#ifdef CONFIG_RAW_DNS
uint32_t entry_cap;
struct gwp_dns_entry **entries;
struct gwp_sockaddr ns_addr;
socklen_t ns_addrlen;
-#endif
volatile bool should_stop;
pthread_mutex_t lock;
pthread_cond_t cond;
@@ -137,7 +131,7 @@ static inline struct gwp_dns_entry *gwp_raw_dns_queue(__maybe_unused uint16_t tx
static inline void gwp_dns_raw_entry_free(__maybe_unused struct gwp_dns_ctx *ctx, __maybe_unused struct gwp_dns_entry *e)
{
}
-#endif
+#endif /* #ifdef CONFIG_RAW_DNS */
/**
* Lookup a DNS entry in the cache. If the entry is found, it fills the
diff --git a/src/gwproxy/ev/epoll.c b/src/gwproxy/ev/epoll.c
index 5926bb5e090a..7c2ff111cefe 100644
--- a/src/gwproxy/ev/epoll.c
+++ b/src/gwproxy/ev/epoll.c
@@ -40,13 +40,11 @@ int gwp_ctx_init_thread_epoll(struct gwp_wrk *w)
}
if (w->ctx->cfg.use_raw_dns) {
-#ifdef CONFIG_RAW_DNS
ev.events = EPOLLIN;
ev.data.u64 = EV_BIT_DNS_QUERY;
r = __sys_epoll_ctl(ep_fd, EPOLL_CTL_ADD, w->dns_resolver.udp_fd, &ev);
if (unlikely(r))
return (int)r;
-#endif
}
w->evsz = 512;
@@ -869,7 +867,7 @@ static int read_raw_dns_answer(__maybe_unused struct gwp_wrk *w,
{
return 0;
}
-#endif
+#endif /* #ifdef CONFIG_RAW_DNS */
static int arm_poll_for_dns_query(struct gwp_wrk *w,
struct gwp_conn_pair *gcp)
diff --git a/src/gwproxy/gwproxy.c b/src/gwproxy/gwproxy.c
index e14780f23945..5afc2f0105ba 100644
--- a/src/gwproxy/gwproxy.c
+++ b/src/gwproxy/gwproxy.c
@@ -45,10 +45,8 @@
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' },
{ "session-map-cap", required_argument, NULL, 's' },
-#endif
{ "event-loop", required_argument, NULL, 'e' },
{ "bind", required_argument, NULL, 'b' },
{ "target", required_argument, NULL, 't' },
@@ -100,10 +98,8 @@ 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",
.sess_map_cap = 16
-#endif
};
__cold
@@ -115,9 +111,7 @@ static void show_help(const char *app)
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);
@@ -245,14 +239,12 @@ 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;
case 's':
cfg->sess_map_cap = atoi(optarg);
break;
-#endif
default:
fprintf(stderr, "Unknown option: %c\n", c);
show_help(argv[0]);
@@ -858,9 +850,7 @@ static int gwp_ctx_init_dns(struct gwp_ctx *ctx)
.cache_expiry = cfg->socks5_dns_cache_secs,
.restyp = cfg->socks5_prefer_ipv6 ? GWP_DNS_RESTYP_PREFER_IPV6 : 0,
.nr_workers = cfg->nr_dns_workers,
-#ifdef CONFIG_RAW_DNS
.ns_addr_str = cfg->ns_addr_str
-#endif
};
int r;
diff --git a/src/gwproxy/gwproxy.h b/src/gwproxy/gwproxy.h
index 9930934b893e..527447cb8dcc 100644
--- a/src/gwproxy/gwproxy.h
+++ b/src/gwproxy/gwproxy.h
@@ -46,10 +46,8 @@ struct gwp_cfg {
int log_level;
const char *log_file;
const char *pid_file;
-#ifdef CONFIG_RAW_DNS
const char *ns_addr_str;
int sess_map_cap;
-#endif
};
struct gwp_ctx;
@@ -215,10 +213,8 @@ struct dns_resolver {
struct gwp_wrk {
int tcp_fd;
-#ifdef CONFIG_RAW_DNS
/* For mapping DNS queries to the corresponding proxy session */
struct dns_resolver dns_resolver;
-#endif
struct gwp_conn_slot conn_slot;
union {
@@ -337,7 +333,7 @@ static inline int return_txid(__maybe_unused struct gwp_wrk *w, __maybe_unused s
{
return 0;
}
-#endif
+#endif /* #ifdef CONFIG_RAW_DNS */
static inline void gwp_conn_buf_advance(struct gwp_conn *conn, size_t len)
{
--
Ahmad Gani
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 5:09 ` [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS Ahmad Gani
@ 2025-09-14 12:16 ` Ammar Faizi
2025-09-14 14:26 ` Alviro Iskandar Setiawan
2025-09-14 17:44 ` Ahmad Gani
0 siblings, 2 replies; 24+ messages in thread
From: Ammar Faizi @ 2025-09-14 12:16 UTC (permalink / raw)
To: Ahmad Gani; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 12:09:40PM +0700, Ahmad Gani wrote:
> No need to wrap struct members in #ifdef, adding a couple of bytes isn't
> a big deal.
Then why did you add it in the first place?
Again, don't add a patch to undo your previous patch. Something like
this should just be squashed. How many times more should I tell you
this again?
Please stop vibe-coding.
I have been observing your patch submissions since July and I saw
various characters that don't actually exist on keyboard in your commit.
And I believe it's a very clear indication that it was not written via
a keyboard, but copy-pasted from somewhere else, likely AIs.
I did not have problems with your prior patches, but your habbit being
driven by AIs in writing patches is not actually healthy down the road.
Especially, when you're working on more complex things like this, the
result is horribly ridiculous.
It's fine to use AI, but it's not fine to let AI dominate your work.
--
Ammar Faizi
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 12:16 ` Ammar Faizi
@ 2025-09-14 14:26 ` Alviro Iskandar Setiawan
2025-09-14 17:45 ` Ahmad Gani
2025-09-14 17:44 ` Ahmad Gani
1 sibling, 1 reply; 24+ messages in thread
From: Alviro Iskandar Setiawan @ 2025-09-14 14:26 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Ahmad Gani, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 7:16 PM Ammar Faizi wrote:
> Please stop vibe-coding.
Oh, that explains why he keeps making the same mistake even if we told
him multiple times not to. It seems the AI he used is not smart enough
to do C programming.
I honestly started feeling weird since he sent the buggy realloc()
code repeatedly. It took 2-3 times to tell him until it eventually got
fixed.
Ahmad Gani, did you really use AI to write patches?
If yes, that's very disgusting because you did not even validate what
the generated result was.
I am not interested in reviewing your AI generated stuff. At least
please take time to validate what the AI throws at you. Stop dumping
bad quality AI generated stuff to the list please.
When you get comments on code review, please address those properly.
Avoid repeating the same mistake too many times.
It happens once, fine, it happens twice, still fine, it happens for
the third times, something is wrong with you. Moreover the mistake you
did just get warned recently.
I am not saying it's forbidden to use AI, but don't let it degrade
your workflow and code quality.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 14:26 ` Alviro Iskandar Setiawan
@ 2025-09-14 17:45 ` Ahmad Gani
2025-09-14 17:59 ` Alviro Iskandar Setiawan
0 siblings, 1 reply; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 17:45 UTC (permalink / raw)
To: Alviro Iskandar Setiawan; +Cc: Ammar Faizi, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 9:26 PM Alviro Iskandar Setiawan wrote:
> On Sun, Sep 14, 2025 at 7:16 PM Ammar Faizi wrote:
> > Please stop vibe-coding.
>
> Oh, that explains why he keeps making the same mistake even if we told
> him multiple times not to. It seems the AI he used is not smart enough
> to do C programming.
Since the rise of AI-stuff, It's easy to jump to conclusions these days.
People started to correlate all things to it, as if all explanations
could magically be hidden under the word AI.
You know what maomao said? stop conjecturing. /j
> Ahmad Gani, did you really use AI to write patches?
I often worry about my grammar and fluency in English, so I used AI to
fix that. Not to generate completely new words, but to polish my sentences.
> When you get comments on code review, please address those properly.
> Avoid repeating the same mistake too many times.
>
> It happens once, fine, it happens twice, still fine, it happens for
> the third times, something is wrong with you. Moreover the mistake you
> did just get warned recently.
People make mistakes, multiple times? yeah that's not normal, but
abnormal people do exist in this world.and I hope you can accept these
kinds of people and not give up on guiding them.
Anyway, I accept the criticism and will try to put more thought before
sending the next patchset.
--
Ahmad Gani
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 17:45 ` Ahmad Gani
@ 2025-09-14 17:59 ` Alviro Iskandar Setiawan
2025-09-14 18:13 ` Ahmad Gani
2025-09-15 2:21 ` Alviro Iskandar Setiawan
0 siblings, 2 replies; 24+ messages in thread
From: Alviro Iskandar Setiawan @ 2025-09-14 17:59 UTC (permalink / raw)
To: Ahmad Gani; +Cc: Ammar Faizi, GNU/Weeb Mailing List
On Mon, Sep 15, 2025 at 12:45 AM Ahmad Gani wrote:
> Since the rise of AI-stuff, It's easy to jump to conclusions these days.
> People started to correlate all things to it, as if all explanations
> could magically be hidden under the word AI.
>
> You know what maomao said? stop conjecturing. /j
I am open to being convinced wrong. I apologize for the wrong conclusion.
> I often worry about my grammar and fluency in English, so I used AI to
> fix that. Not to generate completely new words, but to polish my sentences.
I see, that's fine.
> People make mistakes, multiple times? yeah that's not normal, but
> abnormal people do exist in this world.and I hope you can accept these
> kinds of people and not give up on guiding them.
But repeating the same mistake over and over again even if you've
recently been warned gives me an impression that you ignore comments.
Outliers do exist. But please do your best not to repeat the same
mistake too many times. Please?
> Anyway, I accept the criticism and will try to put more thought before
> sending the next patchset.
Sure, tq.
BTW, I have started a local branch on my machine and cherry picked
some of your patches. Give me several hours. I'll be back to it. Don't
start working on v12 for now.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 17:59 ` Alviro Iskandar Setiawan
@ 2025-09-14 18:13 ` Ahmad Gani
2025-09-15 2:21 ` Alviro Iskandar Setiawan
1 sibling, 0 replies; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 18:13 UTC (permalink / raw)
To: Alviro Iskandar Setiawan; +Cc: Ammar Faizi, GNU/Weeb Mailing List
On Mon, Sep 15, 2025 at 12:59 AM Alviro Iskandar Setiawan wrote:
> On Mon, Sep 15, 2025 at 12:45 AM Ahmad Gani wrote:
> > People make mistakes, multiple times? yeah that's not normal, but
> > abnormal people do exist in this world.and I hope you can accept these
> > kinds of people and not give up on guiding them.
>
> But repeating the same mistake over and over again even if you've
> recently been warned gives me an impression that you ignore comments.
>
> Outliers do exist. But please do your best not to repeat the same
> mistake too many times. Please?
Okay, I will try my best.
> BTW, I have started a local branch on my machine and cherry picked
> some of your patches. Give me several hours. I'll be back to it. Don't
> start working on v12 for now.
I see, I'll get some sleep then, preparing for morning class, good night.
--
Ahmad Gani
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 17:59 ` Alviro Iskandar Setiawan
2025-09-14 18:13 ` Ahmad Gani
@ 2025-09-15 2:21 ` Alviro Iskandar Setiawan
1 sibling, 0 replies; 24+ messages in thread
From: Alviro Iskandar Setiawan @ 2025-09-15 2:21 UTC (permalink / raw)
To: Ahmad Gani; +Cc: Ammar Faizi, GNU/Weeb Mailing List
On Mon, Sep 15, 2025 at 12:59 AM Alviro Iskandar Setiawan wrote:
> BTW, I have started a local branch on my machine and cherry picked
> some of your patches. Give me several hours. I'll be back to it. Don't
> start working on v12 for now.
Temporary saved my unfinished work here
https://github.com/alviroiskandar/gwproxy/commits/new-dns-resolver
I'll check back in tomorrow, need to go somewhere now. You don't need
to work on v12, I'll do it.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 12:16 ` Ammar Faizi
2025-09-14 14:26 ` Alviro Iskandar Setiawan
@ 2025-09-14 17:44 ` Ahmad Gani
2025-09-14 19:02 ` Ammar Faizi
2025-09-15 2:50 ` Alviro Iskandar Setiawan
1 sibling, 2 replies; 24+ messages in thread
From: Ahmad Gani @ 2025-09-14 17:44 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 7:16 PM Ammar Faizi wrote:
> On Sun, Sep 14, 2025 at 12:09:40PM +0700, Ahmad Gani wrote:
> > No need to wrap struct members in #ifdef, adding a couple of bytes isn't
> > a big deal.
>
> Then why did you add it in the first place?
Well, I think to reduce the code size, but after a second thought if
using too many #ifdef is considered bad, then I just need to delete it.
> Again, don't add a patch to undo your previous patch. Something like
> this should just be squashed. How many times more should I tell you
> this again?
Err... sorry, it seems I was too hasty in preparing this patchset and
forgot about this....
> Please stop vibe-coding.
The only code that's written by AI is enum and struct in dnsparser.h and
that's also because at that time you say it's more effective to do so
than manually (I agree with this).
But if your definition of vibe-coding is to code without paying attention
to what you write, then you might be right.
My seriousness depends on whether I enjoyed the activity or not, and I
enjoy the first time I learn and understand about new things but now I
wonder why I'm not as excited as the first time I experienced it.
I need to find a way to restore this feeling.
--
Ahmad Gani
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 17:44 ` Ahmad Gani
@ 2025-09-14 19:02 ` Ammar Faizi
2025-09-15 2:50 ` Alviro Iskandar Setiawan
1 sibling, 0 replies; 24+ messages in thread
From: Ammar Faizi @ 2025-09-14 19:02 UTC (permalink / raw)
To: Ahmad Gani; +Cc: Alviro Iskandar Setiawan, GNU/Weeb Mailing List
On Mon, Sep 15, 2025 at 12:44:31AM +0700, Ahmad Gani wrote:
> But if your definition of vibe-coding is to code without paying attention
> to what you write, then you might be right.
>
> My seriousness depends on whether I enjoyed the activity or not, and I
> enjoy the first time I learn and understand about new things but now I
> wonder why I'm not as excited as the first time I experienced it.
This had better be done seriously, or not at all.
I can't force unpaid people to work on this project. But as a
maintainer, I have the ultimate power to reject bad things come into
this project based on my judgement.
I am not happy seeing something *clearly noted* not being done
seriously coming into this project.
If you don't want to fix your work because you're no longer exicited,
you had better stop. Look at what Alviro did. He spent his time and
energy to review your patches seriously. Several weeks ago, he even
offered you help by taking over this work if you want to stop.
The whole open source idea is that people do what they care about and
what they are good at, and exactly because they aren't forced to deal
with issues they don't have a heart for, they take more pride and
interest in the stuff they do.
--
Ammar Faizi
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS
2025-09-14 17:44 ` Ahmad Gani
2025-09-14 19:02 ` Ammar Faizi
@ 2025-09-15 2:50 ` Alviro Iskandar Setiawan
1 sibling, 0 replies; 24+ messages in thread
From: Alviro Iskandar Setiawan @ 2025-09-15 2:50 UTC (permalink / raw)
To: Ahmad Gani; +Cc: Ammar Faizi, GNU/Weeb Mailing List
On Mon, Sep 15, 2025 at 12:45 AM Ahmad Gani wrote:
> My seriousness depends on whether I enjoyed the activity or not, and I
> enjoy the first time I learn and understand about new things but now I
> wonder why I'm not as excited as the first time I experienced it.
I am very sorry that you're no longer excited about this project.
Anyway, you can stop working on this project if so. I feel bad seeing
you doing things that you don't like. Besides, I only want to review
serious work. I hope you did not get the impression that you're
getting forced to do all of this. No stress please.
I want to thank you for your contribution, I really appreciate your
DNS parser work, that's probably the most useful stepping stone for me
to integrate the raw DNS feature. You're a good programmer to me.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: (subset) [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy
2025-09-14 5:09 [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ahmad Gani
` (5 preceding siblings ...)
2025-09-14 5:09 ` [PATCH gwproxy v11 6/6] gwproxy: Reduce #ifdef CONFIG_RAW_DNS Ahmad Gani
@ 2025-09-14 12:51 ` Ammar Faizi
2025-09-14 17:22 ` Alviro Iskandar Setiawan
7 siblings, 0 replies; 24+ messages in thread
From: Ammar Faizi @ 2025-09-14 12:51 UTC (permalink / raw)
To: Ahmad Gani; +Cc: Ammar Faizi, Alviro Iskandar Setiawan, GNU/Weeb Mailing List
Applied, thanks!
[1/6] dns: Use __sys_close instead of close
commit: 60c6c822cf8ab14d80800776435417238ea371b0
Best regards,
--
Ammar Faizi
^ permalink raw reply [flat|nested] 24+ messages in thread* Re: [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy
2025-09-14 5:09 [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ahmad Gani
` (6 preceding siblings ...)
2025-09-14 12:51 ` (subset) [PATCH gwproxy v11 0/6] Initial work on integration of DNS parser lib in gwproxy Ammar Faizi
@ 2025-09-14 17:22 ` Alviro Iskandar Setiawan
2025-09-14 18:07 ` Ahmad Gani
7 siblings, 1 reply; 24+ messages in thread
From: Alviro Iskandar Setiawan @ 2025-09-14 17:22 UTC (permalink / raw)
To: Ahmad Gani; +Cc: Ammar Faizi, GNU/Weeb Mailing List
On Sun, Sep 14, 2025 at 12:09 PM Ahmad Gani wrote:
> This is revision v11 of the initial work on the integration of the DNS
> parser lib in gwproxy.
I probably can help co-authoring this series. I'll get back to it later.
^ permalink raw reply [flat|nested] 24+ messages in thread