about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2024-09-28 13:58:46 +0000
committerLaurent Bercot <ska@appnovation.com>2024-09-28 13:58:46 +0000
commit645894afb11a4c5d60b4d4f6b55ba3c2f764d1c7 (patch)
treeb79811926d0ea6fd3aea534b155723288db4c5d0
parent36aac3b7052792acd25aceeb7d0498474988a197 (diff)
downloaddnsfunnel-645894afb11a4c5d60b4d4f6b55ba3c2f764d1c7.tar.gz
dnsfunnel-645894afb11a4c5d60b4d4f6b55ba3c2f764d1c7.tar.xz
dnsfunnel-645894afb11a4c5d60b4d4f6b55ba3c2f764d1c7.zip
Prepare for 0.0.2.0; make it work on ipv6
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--NEWS4
-rw-r--r--doc/dnsfunneld.html9
-rw-r--r--doc/index.html2
-rw-r--r--doc/upgrade.html3
-rw-r--r--package/info2
-rw-r--r--src/dnsfunnel/dnsfunneld.c42
-rw-r--r--src/dnsfunnel/dnsfunneld.h10
-rw-r--r--src/dnsfunnel/dnsfunneld_answer.c14
-rw-r--r--src/dnsfunnel/dnsfunneld_process.c2
9 files changed, 44 insertions, 44 deletions
diff --git a/NEWS b/NEWS
index 63c84ce..0aad5c7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,9 @@
 Changelog for dnsfunnel.
 
-In 0.0.1.7
+In 0.0.2.0
 ----------
 
- - Align on rest of skaware.
+ - dnsfunneld can now listen on IPv6 addresses.
 
 
 In 0.0.1.6
diff --git a/doc/dnsfunneld.html b/doc/dnsfunneld.html
index ae03cf1..48ea870 100644
--- a/doc/dnsfunneld.html
+++ b/doc/dnsfunneld.html
@@ -34,8 +34,8 @@ queries, the responses, or both.
 
 <ul>
  <li> dnsfunneld creates a UDP inet domain socket and binds it
-to IPv4 address <em>ip</em> (normally 127.0.0.1) and port <em>port</em>
-(normally 53). </li>
+to IP (v4 or v6) address <em>ip</em> (by default 127.0.0.1) and
+port <em>port</em> (normally 53). </li>
  <li> Depending on the options it has been given, it may chroot and lose
 privileges on its gid and uid. </li>
  <li> It reads the <tt>caches</tt> file (relative to its current
@@ -86,7 +86,7 @@ in the GID environment variable, and drop privileges to that uid/gid. </li>
  <li> <tt>-g&nbsp;<em>gid</em></tt>&nbsp;: drop privileges to numerical gid
 <em>gid</em>. </li>
  <li> <tt>-i&nbsp;<em>ip</em></tt>&nbsp;: bind the socket to
-IPv4 <em>ip</em>. Default is <tt>127.0.0.1</tt>. </li>
+IP address <em>ip</em>. Default is <tt>127.0.0.1</tt>. </li>
  <li> <tt>-p&nbsp;<em>port</em></tt>&nbsp;: bind the socket to
 port <em>port</em>. Default is <tt>53</tt>. </li>
  <li> <tt>-R&nbsp;<em>root</em></tt>&nbsp;: chroot to <em>root</em>. Default
@@ -201,6 +201,9 @@ changes on the <tt>/etc/resolv.conf</tt> file (via inotify or kqueue,
 depending on your system) and immediately calling
 <a href="dnsfunnel-translate.html">dnsfunnel-translate</a>, sending
 a SIGHUP to dnsfunneld, and forcefully overwriting <tt>/etc/resolv.conf</tt>. </li>
+ <li> dnsfunneld can also be used as a simple forwarder, for instance to
+transmit DNS queries arriving on an IPv6 address to a DNS cache that only
+listens to IPv4 addresses. </li>
  <li> It is easy to send a SIGHUP to dnsfunneld even without knowing its
 pid, if it is run under a process supervision system such as
 <a href="//skarnet.org/software/s6/">s6</a>. </li>
diff --git a/doc/index.html b/doc/index.html
index a1648c5..ba3dadd 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -65,7 +65,7 @@ library. </li>
 
 <ul>
  <li> The current released version of dnsfunnel is
-<a href="dnsfunnel-0.0.1.7.tar.gz">0.0.1.7</a>.
+<a href="dnsfunnel-0.0.2.0.tar.gz">0.0.2.0</a>.
 (dnsfunnel is in beta development at the moment. Use at your own
 risk.) </li>
  <li> Alternatively, you can checkout a copy of the
diff --git a/doc/upgrade.html b/doc/upgrade.html
index f478bdc..8f83451 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -18,7 +18,7 @@
 
 <h1> What has changed in dnsfunnel </h1>
 
-<h2> in 0.0.1.7 </h2>
+<h2> in 0.0.2.0 </h2>
 
 <ul>
  <li> <a href="//skarnet.org/software/skalibs/">skalibs</a> dependency bumped to
@@ -27,6 +27,7 @@
 2.3.8.0. </li>
  <li> Static libraries (if any, which isn't the case for now)
 are installed in <tt>/usr/lib</tt> by default. </li>
+ <li> <a href="dnsfunneld.html">dnsfunneld</a> can now listen on IPv6 addresses. </a>
 </ul>
 
 <h2> in 0.0.1.6 </h2>
diff --git a/package/info b/package/info
index 44f9e4b..d1e9959 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
 package=dnsfunnel
-version=0.0.1.7
+version=0.0.2.0
 category=web
 package_macro_name=DNSFUNNEL
diff --git a/src/dnsfunnel/dnsfunneld.c b/src/dnsfunnel/dnsfunneld.c
index 61e2cc1..f57b265 100644
--- a/src/dnsfunnel/dnsfunneld.c
+++ b/src/dnsfunnel/dnsfunneld.c
@@ -31,6 +31,7 @@
 #include <skalibs/iopause.h>
 #include <skalibs/selfpipe.h>
 #include <skalibs/gensetdyn.h>
+#include <skalibs/ip46.h>
 
 #include <s6-dns/s6dns.h>
 
@@ -42,6 +43,8 @@
 #define DNSFUNNELD_INPUT_MAX 64
 
 unsigned int verbosity = 1 ;
+unsigned int ipsz = 4 ;
+
 static tain globaltto ;
 static int cont = 1 ;
 static s6dns_ip46list_t cachelist ;
@@ -110,14 +113,13 @@ static uint32_t sentinel ;
 #define inflight (gensetdyn_n(&queries) - 1)
 #define QUERY(i) GENSETDYN_P(dfquery_t, &queries, i)
 
-void query_new (s6dns_domain_t const *d, uint16_t qtype, uint16_t id, uint32_t ip, uint16_t port, uint32_t procid)
+void query_new (s6dns_domain_t const *d, uint16_t qtype, uint16_t id, char const *ip, uint16_t port, uint32_t procid)
 {
   dfquery_t q =
   {
     .next = QUERY(sentinel)->next,
     .xindex = 0,
     .procid = procid,
-    .ip = ip,
     .port = port,
     .id = id,
     .dt = S6DNS_ENGINE_ZERO
@@ -125,6 +127,7 @@ void query_new (s6dns_domain_t const *d, uint16_t qtype, uint16_t id, uint32_t i
   s6dns_domain_t dd = *d ;
   tain deadline ;
   uint32_t i ;
+  memcpy(q.ip, ip, ipsz) ;
   if (!gensetdyn_new(&queries, &i))
     strerr_diefu1sys(111, "create new query") ;
   s6dns_domain_encode(&dd) ;
@@ -135,10 +138,9 @@ void query_new (s6dns_domain_t const *d, uint16_t qtype, uint16_t id, uint32_t i
   QUERY(sentinel)->next = i ;
 }
 
-static inline void sanitize_and_new (char const *buf, unsigned int len, char const *ippack, uint16_t port)
+static inline void sanitize_and_new (char const *buf, unsigned int len, char const *ip, uint16_t port)
 {
   s6dns_domain_t d ;
-  uint32_t ip ;
   unsigned int pos ;
   s6dns_message_header_t hdr ;
   s6dns_message_counts_t counts ;
@@ -150,20 +152,10 @@ static inline void sanitize_and_new (char const *buf, unsigned int len, char con
    || hdr.counts.qd != 1 || hdr.counts.an || hdr.counts.ns || hdr.counts.nr
    || !s6dns_message_parse_question(&counts, &d, &qtype, buf, len, &pos))
     return ;
-  uint32_unpack_big(ippack, &ip) ;
   if (ops) query_process_question(ops, &d, qtype, hdr.id, ip, port) ;
   else query_new(&d, qtype, hdr.id, ip, port, 0) ;
 }
 
-static inline size_t ip40_scan (char const *s, char *ip)
-{
-  char t[4] ;
-  size_t l = ip4_scan(s, t) ;
-  if (!l || s[l]) return 0 ;
-  memcpy(ip, t, 4) ;
-  return l ;
-}
-
 int main (int argc, char const *const *argv)
 {
   int spfd = -1 ;
@@ -178,9 +170,10 @@ int main (int argc, char const *const *argv)
     int notif = 0 ;
     int fd ;
     unsigned int t = 0 ;
-    char ip[4] = { 127, 0, 0, 1 } ;
-    uint16_t port = 53 ;
     subgetopt l = SUBGETOPT_ZERO ;
+    uint16_t port = 53 ;
+    ip46 ip ;
+    (void)ip46_from_ip4(&ip, IP4_LOCAL) ;
 
     for (;;)
     {
@@ -193,7 +186,7 @@ int main (int argc, char const *const *argv)
         case 'U' : flagU = 1 ; break ;
         case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ;
         case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ;
-        case 'i' : if (!ip40_scan(l.arg, ip)) dieusage() ; break ;
+        case 'i' : if (!ip46_scan(l.arg, &ip)) dieusage() ; break ;
         case 'p' : if (!uint160_scan(l.arg, &port)) dieusage() ; break ;
         case 'R' : root = l.arg ; break ;
         case 'b' : if (!uint0_scan(l.arg, &bufsize)) dieusage() ; break ;
@@ -214,13 +207,14 @@ int main (int argc, char const *const *argv)
       if (notif) strerr_dief1sys(100, "option -1 given but stdout unavailable") ;
     }
     else if (!notif) close(1) ;
-    fd = socket_udp4() ;
+    ipsz = ip46_is6(&ip) ? 16 : 4 ;
+    fd = socket_udp46(ip46_is6(&ip)) ;
     if (fd < 0) strerr_diefu1sys(111, "create UDP socket") ;
-    if (socket_bind4_reuse(fd, ip, port) < 0)
+    if (socket_bind46_reuse(fd, &ip, port) < 0)
     {
-      char fmti[IP4_FMT] ;
+      char fmti[IP46_FMT] ;
       char fmtp[UINT16_FMT] ;
-      fmti[ip4_fmt(fmti, ip)] = 0 ;
+      fmti[ip46_fmt(fmti, &ip)] = 0 ;
       fmtp[uint16_fmt(fmtp, port)] = 0 ;
       strerr_diefu4sys(111, "bind on ip ", fmti, " port ", fmtp) ;
     }
@@ -383,10 +377,10 @@ int main (int argc, char const *const *argv)
       uint32_t n = DNSFUNNELD_INPUT_MAX ;
       while (n--)
       {
-        char ip[4] ;
-        uint16_t port ;
         char buf[512] ;
-        ssize_t r = socket_recv4(0, buf, 512, ip, &port) ;
+        char ip[16] ;
+        uint16_t port ;
+        ssize_t r = ipsz == 16 ? socket_recv6(0, buf, 512, ip, &port) : socket_recv4(0, buf, 512, ip, &port) ;
         if (r < 0)
           if (error_isagain(errno)) break ;
           else strerr_diefu1sys(111, "socket_recv") ;
diff --git a/src/dnsfunnel/dnsfunneld.h b/src/dnsfunnel/dnsfunneld.h
index 4b9acd3..e4d5d64 100644
--- a/src/dnsfunnel/dnsfunneld.h
+++ b/src/dnsfunnel/dnsfunneld.h
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include <skalibs/gensetdyn.h>
+#include <skalibs/ip46.h>
 
 #include <s6-dns/s6dns-domain.h>
 #include <s6-dns/s6dns-engine.h>
@@ -17,14 +18,15 @@ struct dfquery_s
   uint32_t next ;
   uint32_t xindex ;
   uint32_t procid ;
-  uint32_t ip ;
+  char ip[SKALIBS_IP_SIZE] ;
   uint16_t port ;
   uint16_t id ;
   s6dns_engine_t dt ;
 } ;
-#define DFQUERY_ZERO { .next = 0, .xindex = 0, .procid = 0, .ip = 0, .port = 0, .id = 0, .dt = S6DNS_ENGINE_ZERO }
+#define DFQUERY_ZERO { .next = 0, .xindex = 0, .procid = 0, .ip = { 0 }, .port = 0, .id = 0, .dt = S6DNS_ENGINE_ZERO }
 
 extern unsigned int verbosity ;
+extern unsigned int ipsz ;
 extern size_t dfanswer_pending (void) ;
 extern int dfanswer_flush (void) ;
 extern void dfanswer_fail (dfquery_t const *, int) ;
@@ -33,11 +35,11 @@ extern void dfanswer_nodata (dfquery_t const *, int) ;
 extern void dfanswer_pass (dfquery_t const *, char *, unsigned int) ;
 
 
-extern void query_new (s6dns_domain_t const *, uint16_t, uint16_t, uint32_t, uint16_t, uint32_t) ;
+extern void query_new (s6dns_domain_t const *, uint16_t, uint16_t, char const *, uint16_t, uint32_t) ;
 
 extern int query_process_init (void) ;
 extern void query_process_reload (void) ;
-extern void query_process_question (uint32_t, s6dns_domain_t const *, uint16_t, uint16_t, uint32_t, uint16_t) ;
+extern void query_process_question (uint32_t, s6dns_domain_t const *, uint16_t, uint16_t, char const *, uint16_t) ;
 extern void query_process_response_failure (uint32_t, dfquery_t const *) ;
 extern void query_process_response_success (uint32_t, dfquery_t const *) ;
 
diff --git a/src/dnsfunnel/dnsfunneld_answer.c b/src/dnsfunnel/dnsfunneld_answer.c
index 4266089..c16c280 100644
--- a/src/dnsfunnel/dnsfunneld_answer.c
+++ b/src/dnsfunnel/dnsfunneld_answer.c
@@ -24,7 +24,7 @@ size_t dfanswer_pending ()
   return q.len - head ;
 }
 
-static void dfanswer_push (char const *s, size_t len, uint32_t ip, uint16_t port)
+static void dfanswer_push (char const *s, size_t len, char const *ip, uint16_t port)
 {
   if (len > 512)
   {
@@ -33,10 +33,10 @@ static void dfanswer_push (char const *s, size_t len, uint32_t ip, uint16_t port
   }
   else
   {
-    if (!stralloc_readyplus(&q, len + 8)) strerr_diefu1sys(111, "queue answer to client") ;
-    uint32_pack_big(q.s + q.len, ip) ; q.len += 4 ;
+    if (!stralloc_readyplus(&q, len + 4 + ipsz)) strerr_diefu1sys(111, "queue answer to client") ;
     uint16_pack_big(q.s + q.len, port) ; q.len += 2 ;
     uint16_pack_big(q.s + q.len, len) ; q.len += 2 ;
+    memcpy(q.s + q.len, ip, ipsz) ; q.len += ipsz ;
     memcpy(q.s + q.len, s, len) ; q.len += len ;
   }
 }
@@ -46,11 +46,11 @@ int dfanswer_flush ()
   while (dfanswer_pending())
   {
     uint16_t port, len ;
-    uint16_unpack_big(q.s + head + 4, &port) ;
-    uint16_unpack_big(q.s + head + 6, &len) ;
-    if (socket_send4(0, q.s + head + 8, len, q.s + head, port) < 0)
+    uint16_unpack_big(q.s + head, &port) ;
+    uint16_unpack_big(q.s + head + 2, &len) ;
+    if ((ipsz == 16 ? socket_send6(0, q.s + head + 20, len, q.s + head + 4, port) : socket_send4(0, q.s + head + 8, len, q.s + head + 4, port)) < 0)
       return error_isagain(errno) ? (errno = 0, 0) : -1 ;
-    head += len + 8 ;
+    head += 4 + ipsz + len ;
     if ((q.len - head) >> 2 <= q.len)
     {
       memmove(q.s, q.s + head, q.len - head) ;
diff --git a/src/dnsfunnel/dnsfunneld_process.c b/src/dnsfunnel/dnsfunneld_process.c
index 5f28a37..9ccdf2e 100644
--- a/src/dnsfunnel/dnsfunneld_process.c
+++ b/src/dnsfunnel/dnsfunneld_process.c
@@ -25,7 +25,7 @@ void query_process_reload ()
 {
 }
 
-void query_process_question (uint32_t ops, s6dns_domain_t const *d, uint16_t qtype, uint16_t id, uint32_t ip, uint16_t port)
+void query_process_question (uint32_t ops, s6dns_domain_t const *d, uint16_t qtype, uint16_t id, char const *ip, uint16_t port)
 {
   if (ops & 2 && (qtype == S6DNS_T_A || qtype == S6DNS_T_AAAA))
   {