]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Add (stub|forward)-tcp-upstream options which enable using tcp transport only for... 519/head
authorTomasz Ziolkowski <tomasz.ziolkowski@allegro.pl>
Thu, 5 Aug 2021 06:44:18 +0000 (08:44 +0200)
committerTomasz Ziolkowski <tomasz.ziolkowski@allegro.pl>
Thu, 5 Aug 2021 06:44:18 +0000 (08:44 +0200)
28 files changed:
daemon/worker.c
doc/unbound.conf.5.in
iterator/iter_delegpt.c
iterator/iter_delegpt.h
iterator/iter_fwd.c
iterator/iter_hints.c
iterator/iterator.c
libunbound/libworker.c
libunbound/worker.h
smallapp/worker_cb.c
testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.conf [new file with mode: 0644]
testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.dsc [new file with mode: 0644]
testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.post [new file with mode: 0644]
testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.pre [new file with mode: 0644]
testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.test [new file with mode: 0644]
testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.testns [new file with mode: 0644]
testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.conf [new file with mode: 0644]
testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.dsc [new file with mode: 0644]
testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.post [new file with mode: 0644]
testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.pre [new file with mode: 0644]
testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.test [new file with mode: 0644]
testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.testns [new file with mode: 0644]
util/config_file.h
util/configlexer.lex
util/configparser.y
util/fptr_wlist.c
util/fptr_wlist.h
util/module.h

index e9e163a0448b438e3d3cb8c9d808707bffd095e7..b994645b4dc0c51e7b7b8bf36bd10b8b36aff046 100644 (file)
@@ -1988,8 +1988,8 @@ worker_delete(struct worker* worker)
 struct outbound_entry*
 worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
        int want_dnssec, int nocaps, struct sockaddr_storage* addr,
-       socklen_t addrlen, uint8_t* zone, size_t zonelen, int ssl_upstream,
-       char* tls_auth_name, struct module_qstate* q)
+       socklen_t addrlen, uint8_t* zone, size_t zonelen, int tcp_upstream,
+       int ssl_upstream, char* tls_auth_name, struct module_qstate* q)
 {
        struct worker* worker = q->env->worker;
        struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -1998,7 +1998,7 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
                return NULL;
        e->qstate = q;
        e->qsent = outnet_serviced_query(worker->back, qinfo, flags, dnssec,
-               want_dnssec, nocaps, q->env->cfg->tcp_upstream,
+               want_dnssec, nocaps, tcp_upstream,
                ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
                worker_handle_service_reply, e, worker->back->udp_buff, q->env);
        if(!e->qsent) {
@@ -2045,7 +2045,7 @@ struct outbound_entry* libworker_send_query(
        uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
        int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
        struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
-       uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
+       uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
        int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
        struct module_qstate* ATTR_UNUSED(q))
 {
index d5315d53b29a936187e0c8c213d6041972937356..1f7e191ed48d9abfea39f2f770bc32cc82dfcf62 100644 (file)
@@ -485,7 +485,9 @@ advertised timeout.
 .TP
 .B tcp\-upstream: \fI<yes or no>
 Enable or disable whether the upstream queries use TCP only for transport.
-Default is no.  Useful in tunneling scenarios.
+Default is no.  Useful in tunneling scenarios. If set to no you can specify
+TCP transport only for selected forward or stub zones using forward-tcp-upstream
+or stub-tcp-upstream respectively.
 .TP
 .B udp\-upstream\-without\-downstream: \fI<yes or no>
 Enable udp upstream even if do-udp is no.  Default is no, and this does not
@@ -1853,6 +1855,10 @@ Default is no.
 .B stub\-ssl\-upstream: \fI<yes or no>
 Alternate syntax for \fBstub\-tls\-upstream\fR.
 .TP
+.B stub\-tcp\-upstream: \fI<yes or no>
+If it is set to "yes" then upstream queries use TCP only for transport regardless of global flag tcp-upstream.
+Default is no.
+.TP
 .B stub\-no\-cache: \fI<yes or no>
 Default is no.  If enabled, data inside the stub is not cached.  This is
 useful when you want immediate changes to be visible.
@@ -1905,6 +1911,10 @@ load CA certs, otherwise the connections cannot be authenticated.
 .B forward\-ssl\-upstream: \fI<yes or no>
 Alternate syntax for \fBforward\-tls\-upstream\fR.
 .TP
+.B forward\-tcp\-upstream: \fI<yes or no>
+If it is set to "yes" then upstream queries use TCP only for transport regardless of global flag tcp-upstream.
+Default is no.
+.TP
 .B forward\-no\-cache: \fI<yes or no>
 Default is no.  If enabled, data inside the forward is not cached.  This is
 useful when you want immediate changes to be visible.
index 9a672b0af39de132c2500b2c3aed7d1dad930b9c..bdac42b0ddb35bcf107646696adc74d279266997 100644 (file)
@@ -73,6 +73,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
        copy->bogus = dp->bogus;
        copy->has_parent_side_NS = dp->has_parent_side_NS;
        copy->ssl_upstream = dp->ssl_upstream;
+       copy->tcp_upstream = dp->tcp_upstream;
        for(ns = dp->nslist; ns; ns = ns->next) {
                if(!delegpt_add_ns(copy, region, ns->name, ns->lame))
                        return NULL;
index 138eb6e1b60a40febe49dea7280890b586b7cec1..9c8cfb281baeca74e286f300ff10073836562bc3 100644 (file)
@@ -83,6 +83,8 @@ struct delegpt {
        uint8_t dp_type_mlc;
        /** use SSL for upstream query */
        uint8_t ssl_upstream;
+       /** use TCP for upstream query */
+       uint8_t tcp_upstream;
        /** delegpt from authoritative zone that is locally hosted */
        uint8_t auth_dp;
        /*** no cache */
index ea3d70e07320f5b149ec2dac776cb30a1e3bfc92..128007a0412c1f5110206f2ef02e4fbd3165d494 100644 (file)
@@ -276,6 +276,8 @@ read_forwards(struct iter_forwards* fwd, struct config_file* cfg)
                dp->no_cache = s->no_cache;
                /* use SSL for queries to this forwarder */
                dp->ssl_upstream = (uint8_t)s->ssl_upstream;
+               /* use TCP for queries to this forwarder */
+               dp->tcp_upstream = (uint8_t)s->tcp_upstream;
                verbose(VERB_QUERY, "Forward zone server list:");
                delegpt_log(VERB_QUERY, dp);
                if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp))
index 60e518122ed14d1106ce9aed9889ed8d0bf5cb00..2af443d8c6c8d33f3f513752b95bce8fcabd7e1a 100644 (file)
@@ -287,6 +287,8 @@ read_stubs(struct iter_hints* hints, struct config_file* cfg)
                dp->no_cache = s->no_cache;
                /* ssl_upstream */
                dp->ssl_upstream = (uint8_t)s->ssl_upstream;
+               /* tcp_upstream */
+               dp->tcp_upstream = (uint8_t)s->tcp_upstream;
                delegpt_log(VERB_QUERY, dp);
                if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime))
                        return 0;
index f0105ad4b085dee5216eb63b05c7031ffd80d910..efc94c37bf0d5d0f42cc9d3985da648f08e6f067 100644 (file)
@@ -2666,6 +2666,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
                ie, iq), &target->addr, target->addrlen,
                iq->dp->name, iq->dp->namelen,
+               (iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream),
                (iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream),
                target->tls_auth_name, qstate);
        if(!outq) {
index 8a9ca94194807f4c1bc0b50d3d68291d3bcec567..151f50cf599af7703372fd1493a91cbaffb6accf 100644 (file)
@@ -881,7 +881,7 @@ void libworker_alloc_cleanup(void* arg)
 struct outbound_entry* libworker_send_query(struct query_info* qinfo,
        uint16_t flags, int dnssec, int want_dnssec, int nocaps,
        struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
-       size_t zonelen, int ssl_upstream, char* tls_auth_name,
+       size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
        struct module_qstate* q)
 {
        struct libworker* w = (struct libworker*)q->env->worker;
@@ -891,7 +891,7 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
                return NULL;
        e->qstate = q;
        e->qsent = outnet_serviced_query(w->back, qinfo, flags, dnssec,
-               want_dnssec, nocaps, q->env->cfg->tcp_upstream, ssl_upstream,
+               want_dnssec, nocaps, tcp_upstream, ssl_upstream,
                tls_auth_name, addr, addrlen, zone, zonelen, q,
                libworker_handle_service_reply, e, w->back->udp_buff, q->env);
        if(!e->qsent) {
@@ -975,7 +975,7 @@ struct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
        uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
        int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
        struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
-       uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen),
+       uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
        int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
        struct module_qstate* ATTR_UNUSED(q))
 {
index bf7473861af8a21ca871427f073460963f3dcdba..c1fc8e784e4a674bfe4ad0726efbbfd4e5f08dea 100644 (file)
@@ -72,7 +72,7 @@ struct query_info;
 struct outbound_entry* libworker_send_query(struct query_info* qinfo,
        uint16_t flags, int dnssec, int want_dnssec, int nocaps,
        struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
-       size_t zonelen, int ssl_upstream, char* tls_auth_name,
+       size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
        struct module_qstate* q);
 
 /** process incoming serviced query replies from the network */
@@ -123,7 +123,7 @@ void worker_sighandler(int sig, void* arg);
 struct outbound_entry* worker_send_query(struct query_info* qinfo,
        uint16_t flags, int dnssec, int want_dnssec, int nocaps,
        struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
-       size_t zonelen, int ssl_upstream, char* tls_auth_name,
+       size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
        struct module_qstate* q);
 
 /** 
index 473e32a607f8954f416cfab32c37a4571f622420..78e773938c880a52063bfa9dc10cce6c3ef5df29 100644 (file)
@@ -99,7 +99,7 @@ struct outbound_entry* worker_send_query(
        int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
        int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
        socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
-       size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream),
+       size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
        char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q))
 {
        log_assert(0);
@@ -131,7 +131,7 @@ struct outbound_entry* libworker_send_query(
        int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
        int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
        socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
-       size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream),
+       size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
        char* ATTR_UNUSED(tls_auth_name), struct module_qstate* ATTR_UNUSED(q))
 {
        log_assert(0);
diff --git a/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.conf b/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.conf
new file mode 100644 (file)
index 0000000..6daf2ee
--- /dev/null
@@ -0,0 +1,20 @@
+server:
+       verbosity: 5
+       # num-threads: 1
+       interface: 127.0.0.1
+       port: @PORT@
+       use-syslog: no
+       directory: ""
+       pidfile: "unbound.pid"
+       chroot: ""
+       username: ""
+       do-not-query-localhost: no
+forward-zone:
+       name: "tcp.example.com"
+       forward-addr: "127.0.0.1@@TOPORT@"
+       forward-tcp-upstream: "yes"
+forward-zone:
+       name: "udp.example.com"
+       forward-addr: "127.0.0.1@@TOPORT@"
+       forward-tcp-upstream: "no"
+
diff --git a/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.dsc b/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.dsc
new file mode 100644 (file)
index 0000000..5b1f0d3
--- /dev/null
@@ -0,0 +1,16 @@
+BaseName: fwd_udp_with_tcp_upstream
+Version: 1.0
+Description: Forward an UDP packet to upstream via TCP and return reply.
+CreationDate: Thu Aug  5 07:44:41 CEST 2021
+Maintainer: ziollek
+Category: 
+Component:
+CmdDepends: 
+Depends: 
+Help:
+Pre: fwd_udp_with_tcp_upstream.pre
+Post: fwd_udp_with_tcp_upstream.post
+Test: fwd_udp_with_tcp_upstream.test
+AuxFiles: 
+Passed:
+Failure:
diff --git a/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.post b/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.post
new file mode 100644 (file)
index 0000000..0013eca
--- /dev/null
@@ -0,0 +1,10 @@
+# #-- fwd_udp_with_tcp_upstream.post --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# source the test var file when it's there
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+#
+# do your teardown here
+. ../common.sh
+kill_pid $FWD_PID
+kill_pid $UNBOUND_PID
diff --git a/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.pre b/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.pre
new file mode 100644 (file)
index 0000000..546787a
--- /dev/null
@@ -0,0 +1,31 @@
+# #-- fwd_udp_with_tcp_upstream.pre--#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+. ../common.sh
+get_random_port 2
+UNBOUND_PORT=$RND_PORT
+FWD_PORT=$(($RND_PORT + 1))
+echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
+echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
+
+# start forwarder
+get_ldns_testns
+$LDNS_TESTNS -p $FWD_PORT fwd_udp_with_tcp_upstream.testns >fwd.log 2>&1 &
+FWD_PID=$!
+echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
+
+# make config file
+sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < fwd_udp_with_tcp_upstream.conf > ub.conf
+# start unbound in the background
+PRE="../.."
+$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
+UNBOUND_PID=$!
+echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
+
+cat .tpkg.var.test
+wait_ldns_testns_up fwd.log
+wait_unbound_up unbound.log
+
diff --git a/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.test b/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.test
new file mode 100644 (file)
index 0000000..fad6497
--- /dev/null
@@ -0,0 +1,35 @@
+# #-- fwd_udp_with_tcp_upstream.test --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+PRE="../.."
+# do the test
+echo "> dig tcp.example.com."
+dig @localhost -p $UNBOUND_PORT tcp.example.com. | tee outfile
+echo "> cat logfiles"
+cat fwd.log 
+cat unbound.log
+echo "> check answer"
+if grep "10.20.30.40" outfile; then
+       echo "OK"
+else
+       echo "Not OK"
+       exit 1
+fi
+
+echo "> dig udp.example.com."
+dig @localhost -p $UNBOUND_PORT udp.example.com. | tee outfile
+echo "> cat logfiles"
+cat fwd.log
+cat unbound.log
+echo "> check answer"
+if grep "10.20.30.80" outfile; then
+       echo "OK"
+else
+       echo "Not OK"
+       exit 1
+fi
+
+exit 0
diff --git a/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.testns b/testdata/fwd_udp_with_tcp_upstream.tdir/fwd_udp_with_tcp_upstream.testns
new file mode 100644 (file)
index 0000000..04089af
--- /dev/null
@@ -0,0 +1,25 @@
+; nameserver test file
+$ORIGIN example.com.
+$TTL 3600
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+MATCH TCP
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+tcp    IN      A
+SECTION ANSWER
+tcp    IN      A       10.20.30.40
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+MATCH UDP
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+udp    IN      A
+SECTION ANSWER
+udp    IN      A       10.20.30.80
+ENTRY_END
diff --git a/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.conf b/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.conf
new file mode 100644 (file)
index 0000000..d57c787
--- /dev/null
@@ -0,0 +1,19 @@
+server:
+       verbosity: 2
+       # num-threads: 1
+       interface: 127.0.0.1
+       port: @PORT@
+       use-syslog: no
+       directory: ""
+       pidfile: "unbound.pid"
+       chroot: ""
+       username: ""
+       do-not-query-localhost: no
+stub-zone:
+       name: "tcp.example.com"
+       stub-addr: "127.0.0.1@@TOPORT@"
+       stub-tcp-upstream: "yes"
+stub-zone:
+       name: "udp.example.com"
+       stub-addr: "127.0.0.1@@TOPORT@"
+       stub-tcp-upstream: "no"
\ No newline at end of file
diff --git a/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.dsc b/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.dsc
new file mode 100644 (file)
index 0000000..526ff67
--- /dev/null
@@ -0,0 +1,16 @@
+BaseName: stub_udp_with_tcp_upstream
+Version: 1.0
+Description: Stub server contacted via UDP with tcp upstream.
+CreationDate: Thu Aug  5 07:44:41 CEST 2021
+Maintainer: ziollek
+Category: 
+Component:
+CmdDepends: 
+Depends: 
+Help:
+Pre: stub_udp_with_tcp_upstream.pre
+Post: stub_udp_with_tcp_upstream.post
+Test: stub_udp_with_tcp_upstream.test
+AuxFiles: 
+Passed:
+Failure:
diff --git a/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.post b/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.post
new file mode 100644 (file)
index 0000000..c804b6c
--- /dev/null
@@ -0,0 +1,10 @@
+# #-- stub_udp_with_tcp_upstream.post --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# source the test var file when it's there
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+#
+# do your teardown here
+. ../common.sh
+kill_pid $FWD_PID
+kill_pid $UNBOUND_PID
diff --git a/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.pre b/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.pre
new file mode 100644 (file)
index 0000000..2bca63b
--- /dev/null
@@ -0,0 +1,35 @@
+# #-- stub_udp_with_tcp_upstream.pre--#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+. ../common.sh
+
+get_random_port 2
+UNBOUND_PORT=$RND_PORT
+FWD_PORT=$(($RND_PORT + 1))
+echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
+echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
+
+# start forwarder
+get_ldns_testns
+$LDNS_TESTNS -p $FWD_PORT stub_udp_with_tcp_upstream.testns >fwd.log 2>&1 &
+FWD_PID=$!
+echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
+
+# make config file
+sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < stub_udp_with_tcp_upstream.conf > ub.conf
+# start unbound in the background
+PRE="../.."
+$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
+UNBOUND_PID=$!
+echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
+
+cat .tpkg.var.test
+
+# wait for forwarder to come up
+wait_ldns_testns_up fwd.log
+
+# wait for unbound to come up
+wait_unbound_up unbound.log
+
diff --git a/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.test b/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.test
new file mode 100644 (file)
index 0000000..43591ac
--- /dev/null
@@ -0,0 +1,37 @@
+# #-- stub_udp_with_tcp_upstream.test --#
+# source the master var file when it's there
+[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
+# use .tpkg.var.test for in test variable passing
+[ -f .tpkg.var.test ] && source .tpkg.var.test
+
+PRE="../.."
+# do the test
+echo "> dig tcp.example.com."
+dig @127.0.0.1 -p $UNBOUND_PORT tcp.example.com. | tee outfile
+echo "> cat logfiles"
+cat fwd.log 
+cat unbound.log
+echo "> check answer"
+if grep "10.20.30.40" outfile; then
+       echo "OK"
+else
+       echo "Not OK"
+       exit 1
+fi
+
+
+# check if second stub is requested via udp
+echo "> dig udp.example.com."
+dig @127.0.0.1 -p $UNBOUND_PORT udp.example.com. | tee outfile
+echo "> cat logfiles"
+cat fwd.log 
+cat unbound.log
+echo "> check answer"
+if grep "10.20.30.80" outfile; then
+       echo "OK"
+else
+       echo "Not OK"
+       exit 1
+fi
+
+exit 0
diff --git a/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.testns b/testdata/stub_udp_with_tcp_upstream.tdir/stub_udp_with_tcp_upstream.testns
new file mode 100644 (file)
index 0000000..f215541
--- /dev/null
@@ -0,0 +1,48 @@
+; nameserver test file
+$ORIGIN example.com.
+$TTL 3600
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+MATCH TCP
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+tcp    IN      A
+SECTION ANSWER
+tcp    IN      A       10.20.30.40
+SECTION AUTHORITY
+@      IN      NS      ns.example.com.
+SECTION ADDITIONAL
+ns     IN      A       127.0.0.1
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+MATCH UDP
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+udp    IN      A
+SECTION ANSWER
+udp    IN      A       10.20.30.80
+SECTION AUTHORITY
+@      IN      NS      ns.example.com.
+SECTION ADDITIONAL
+ns     IN      A       127.0.0.1
+ENTRY_END
+
+; root prime
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR AA NOERROR
+ADJUST copy_id
+SECTION QUESTION
+.      IN      NS
+SECTION ANSWER
+.      IN      NS      root.server.
+SECTION AUTHORITY
+SECTION ADDITIONAL
+root.server.   IN      A       127.0.0.1
+ENTRY_END
+
index aed6812dafe81f68648c39af5c1c0f834d67670c..b868d9cc8f96fe76acb2dd6432d0858060a3ea04 100644 (file)
@@ -697,6 +697,8 @@ struct config_stub {
        int isprime;
        /** if forward-first is set (failover to without if fails) */
        int isfirst;
+       /** use tcp for queries to this stub */
+       int tcp_upstream;
        /** use SSL for queries to this stub */
        int ssl_upstream;
        /*** no cache */
index dbfc17d499f25a46801d8667287008cf7efac3ec..b1dd3c1ed0cce6932a5c3ae2fec4c6061a28589e 100644 (file)
@@ -331,6 +331,7 @@ stub-first{COLON}           { YDVAR(1, VAR_STUB_FIRST) }
 stub-no-cache{COLON}           { YDVAR(1, VAR_STUB_NO_CACHE) }
 stub-ssl-upstream{COLON}       { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
 stub-tls-upstream{COLON}       { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
+stub-tcp-upstream{COLON}       { YDVAR(1, VAR_STUB_TCP_UPSTREAM) }
 forward-zone{COLON}            { YDVAR(0, VAR_FORWARD_ZONE) }
 forward-addr{COLON}            { YDVAR(1, VAR_FORWARD_ADDR) }
 forward-host{COLON}            { YDVAR(1, VAR_FORWARD_HOST) }
@@ -338,6 +339,7 @@ forward-first{COLON}                { YDVAR(1, VAR_FORWARD_FIRST) }
 forward-no-cache{COLON}                { YDVAR(1, VAR_FORWARD_NO_CACHE) }
 forward-ssl-upstream{COLON}    { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
 forward-tls-upstream{COLON}    { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
+forward-tcp-upstream{COLON}    { YDVAR(1, VAR_FORWARD_TCP_UPSTREAM) }
 auth-zone{COLON}               { YDVAR(0, VAR_AUTH_ZONE) }
 rpz{COLON}                     { YDVAR(0, VAR_RPZ) }
 tags{COLON}                    { YDVAR(1, VAR_TAGS) }
index e22d48d41055815432b1d129c37c2296d3cf66d5..be8fe2dacf1905180acb59f576edec9622b6aa61 100644 (file)
@@ -113,6 +113,7 @@ extern struct config_parser_state* cfg_parser;
 %token VAR_SSL_UPSTREAM VAR_TCP_AUTH_QUERY_TIMEOUT VAR_SSL_SERVICE_KEY
 %token VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
 %token VAR_STUB_SSL_UPSTREAM VAR_FORWARD_SSL_UPSTREAM VAR_TLS_CERT_BUNDLE
+%token VAR_STUB_TCP_UPSTREAM VAR_FORWARD_TCP_UPSTREAM
 %token VAR_HTTPS_PORT VAR_HTTP_ENDPOINT VAR_HTTP_MAX_STREAMS
 %token VAR_HTTP_QUERY_BUFFER_SIZE VAR_HTTP_RESPONSE_BUFFER_SIZE
 %token VAR_HTTP_NODELAY VAR_HTTP_NOTLS_DOWNSTREAM
@@ -324,7 +325,7 @@ stubstart: VAR_STUB_ZONE
 contents_stub: contents_stub content_stub 
        | ;
 content_stub: stub_name | stub_host | stub_addr | stub_prime | stub_first |
-       stub_no_cache | stub_ssl_upstream
+       stub_no_cache | stub_ssl_upstream | stub_tcp_upstream
        ;
 forwardstart: VAR_FORWARD_ZONE
        {
@@ -341,7 +342,7 @@ forwardstart: VAR_FORWARD_ZONE
 contents_forward: contents_forward content_forward 
        | ;
 content_forward: forward_name | forward_host | forward_addr | forward_first |
-       forward_no_cache | forward_ssl_upstream
+       forward_no_cache | forward_ssl_upstream | forward_tcp_upstream
        ;
 viewstart: VAR_VIEW
        {
@@ -2721,6 +2722,16 @@ stub_ssl_upstream: VAR_STUB_SSL_UPSTREAM STRING_ARG
                free($2);
        }
        ;
+stub_tcp_upstream: VAR_STUB_TCP_UPSTREAM STRING_ARG
+        {
+                OUTYY(("P(stub-tcp-upstream:%s)\n", $2));
+                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                        yyerror("expected yes or no.");
+                else cfg_parser->cfg->stubs->tcp_upstream =
+                        (strcmp($2, "yes")==0);
+                free($2);
+        }
+        ;
 stub_prime: VAR_STUB_PRIME STRING_ARG
        {
                OUTYY(("P(stub-prime:%s)\n", $2));
@@ -2783,6 +2794,16 @@ forward_ssl_upstream: VAR_FORWARD_SSL_UPSTREAM STRING_ARG
                free($2);
        }
        ;
+forward_tcp_upstream: VAR_FORWARD_TCP_UPSTREAM STRING_ARG
+        {
+                OUTYY(("P(forward-tcp-upstream:%s)\n", $2));
+                if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                        yyerror("expected yes or no.");
+                else cfg_parser->cfg->forwards->tcp_upstream =
+                        (strcmp($2, "yes")==0);
+                free($2);
+        }
+        ;
 auth_name: VAR_NAME STRING_ARG
        {
                OUTYY(("P(name:%s)\n", $2));
index de6dbd02a37d6b27766be6712b22d9295a7b69bc..f8dac65c59a006fe996ec101014a1977d68d3bd6 100644 (file)
@@ -335,7 +335,7 @@ int
 fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
        struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec,
        int nocaps, struct sockaddr_storage* addr, socklen_t addrlen,
-       uint8_t* zone, size_t zonelen, int ssl_upstream, char* tls_auth_name,
+       uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
        struct module_qstate* q))
 {
        if(fptr == &worker_send_query) return 1;
index cd331febb0701a7bdbe515620228ff5ce5222880..a5470992550f8809ec59e61ea1f99ff074528227 100644 (file)
@@ -212,7 +212,7 @@ int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_type fptr);
 int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
        struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec,
        int nocaps, struct sockaddr_storage* addr, socklen_t addrlen,
-       uint8_t* zone, size_t zonelen, int ssl_upstream, char* tls_auth_name,
+       uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
        struct module_qstate* q));
 
 /**
index 81a31a9cca46c2ee1eb5baae0d47eed90ed7de1d..a463736879d67581fab444d5999e9988663174b1 100644 (file)
@@ -354,6 +354,7 @@ struct module_env {
         * @param addrlen: length of addr.
         * @param zone: delegation point name.
         * @param zonelen: length of zone name.
+        * @param tcp_upstream: use TCP for upstream queries.
         * @param ssl_upstream: use SSL for upstream queries.
         * @param tls_auth_name: if ssl_upstream, use this name with TLS
         *      authentication.
@@ -366,7 +367,7 @@ struct module_env {
        struct outbound_entry* (*send_query)(struct query_info* qinfo,
                uint16_t flags, int dnssec, int want_dnssec, int nocaps,
                struct sockaddr_storage* addr, socklen_t addrlen,
-               uint8_t* zone, size_t zonelen, int ssl_upstream,
+               uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream,
                char* tls_auth_name, struct module_qstate* q);
 
        /**