DNS send, receive and response functions currently infer which server
to use from the non-null member of a nameserver. This is unambiguous
while a nameserver owns only one server, but prevents one logical
nameserver from exposing both datagram and stream servers.

Pass a dns_server_type through these interfaces and add predicates for
readable type checks. Existing queries still select the same server, so
this patch does not change runtime behavior.
---
 include/haproxy/dns-t.h |  7 ++++++-
 include/haproxy/dns.h   | 16 ++++++++++++++--
 src/dns.c               | 20 ++++++++++----------
 src/resolvers.c         | 15 +++++++++------
 4 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/include/haproxy/dns-t.h b/include/haproxy/dns-t.h
index c00075572..58dfb4f47 100644
--- a/include/haproxy/dns-t.h
+++ b/include/haproxy/dns-t.h
@@ -136,6 +136,11 @@ struct dns_session {
        int shutdown;
 };
 
+enum dns_server_type {
+       DNS_SERVER_DGRAM = 0,
+       DNS_SERVER_STREAM,
+};
+
 /* Structure describing a name server
  */
 struct dns_nameserver {
@@ -147,7 +152,7 @@ struct dns_nameserver {
                int         line;       /* line where the section appears */
        } conf;                         /* config information */
 
-       int (*process_responses)(struct dns_nameserver *ns); /* callback used 
to process responses */
+       int (*process_responses)(struct dns_nameserver *ns, enum 
dns_server_type type); /* callback used to process responses */
        struct dns_dgram_server *dgram;  /* used for dgram dns */
        struct dns_stream_server *stream; /* used for tcp dns */
 
diff --git a/include/haproxy/dns.h b/include/haproxy/dns.h
index 3e0cd5939..c929415d0 100644
--- a/include/haproxy/dns.h
+++ b/include/haproxy/dns.h
@@ -25,10 +25,22 @@
 #include <haproxy/dns-t.h>
 #include <haproxy/server-t.h>
 
-int dns_send_nameserver(struct dns_nameserver *ns, void *buf, size_t len);
-ssize_t dns_recv_nameserver(struct dns_nameserver *ns, void *data, size_t 
size);
+int dns_send_nameserver(struct dns_nameserver *ns, enum dns_server_type type, 
void *buf, size_t len);
+ssize_t dns_recv_nameserver(struct dns_nameserver *ns, enum dns_server_type 
type, void *data, size_t size);
 int dns_dgram_init(struct dns_nameserver *ns, struct sockaddr_storage *sk);
 int dns_stream_init(struct dns_nameserver *ns, struct server *s);
 void dns_nameserver_deinit(struct dns_nameserver *ns);
 
+/* Returns nonzero if <type> selects a datagram server. */
+static inline int dns_server_type_is_dgram(enum dns_server_type type)
+{
+       return type == DNS_SERVER_DGRAM;
+}
+
+/* Returns nonzero if <type> selects a stream server. */
+static inline int dns_server_type_is_stream(enum dns_server_type type)
+{
+       return type == DNS_SERVER_STREAM;
+}
+
 #endif // _HAPROXY_DNS_H
diff --git a/src/dns.c b/src/dns.c
index 460af2def..5101a2f70 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -132,16 +132,16 @@ static int dns_connect_nameserver(struct dns_nameserver 
*ns)
        return 0;
 }
 
-/* Sends a message to a name server
+/* Sends a message using server type <type> on nameserver <ns>.
  * It returns message length on success
  * or -1 in error case
  * 0 is returned in case of output ring buffer is full
  */
-int dns_send_nameserver(struct dns_nameserver *ns, void *buf, size_t len)
+int dns_send_nameserver(struct dns_nameserver *ns, enum dns_server_type type, 
void *buf, size_t len)
 {
        int ret = -1;
 
-       if (ns->dgram) {
+       if (dns_server_type_is_dgram(type) && ns->dgram) {
                struct dgram_conn *dgram = &ns->dgram->conn;
                int fd;
 
@@ -190,7 +190,7 @@ int dns_send_nameserver(struct dns_nameserver *ns, void 
*buf, size_t len)
                ns->counters->sent++;
                HA_SPIN_UNLOCK(DNS_LOCK, &dgram->lock);
        }
-       else if (ns->stream) {
+       else if (dns_server_type_is_stream(type) && ns->stream) {
                struct ist myist;
 
                myist = ist2(buf, len);
@@ -208,16 +208,16 @@ int dns_send_nameserver(struct dns_nameserver *ns, void 
*buf, size_t len)
 
 void dns_session_free(struct dns_session *);
 
-/* Receives a dns message
+/* Receives a DNS message using server type <type> on nameserver <ns>.
  * Returns message length
  * 0 is returned if no more message available
  * -1 in error case
  */
-ssize_t dns_recv_nameserver(struct dns_nameserver *ns, void *data, size_t size)
+ssize_t dns_recv_nameserver(struct dns_nameserver *ns, enum dns_server_type 
type, void *data, size_t size)
 {
        ssize_t ret = -1;
 
-       if (ns->dgram) {
+       if (dns_server_type_is_dgram(type) && ns->dgram) {
                struct dgram_conn *dgram = &ns->dgram->conn;
                struct sockaddr_storage from = {0};
                socklen_t fromlen = sizeof(from);
@@ -249,7 +249,7 @@ ssize_t dns_recv_nameserver(struct dns_nameserver *ns, void 
*data, size_t size)
                }
                HA_SPIN_UNLOCK(DNS_LOCK, &dgram->lock);
        }
-       else if (ns->stream) {
+       else if (dns_server_type_is_stream(type) && ns->stream) {
                struct dns_stream_server *dss = ns->stream;
                struct dns_session *ds;
 
@@ -353,7 +353,7 @@ static void dns_resolve_recv(struct dgram_conn *dgram)
 
        HA_SPIN_UNLOCK(DNS_LOCK, &dgram->lock);
 
-       ns->process_responses(ns);
+       ns->process_responses(ns, DNS_SERVER_DGRAM);
 }
 
 /* Called when a dns network socket is ready to send data */
@@ -1336,7 +1336,7 @@ static struct task *dns_process_rsp(struct task *t, void 
*context, unsigned int
 {
        struct dns_nameserver *ns = (struct dns_nameserver *)context;
 
-       ns->process_responses(ns);
+       ns->process_responses(ns, DNS_SERVER_STREAM);
 
        return t;
 }
diff --git a/src/resolvers.c b/src/resolvers.c
index 824cc2d06..c63a1f373 100644
--- a/src/resolvers.c
+++ b/src/resolvers.c
@@ -470,7 +470,10 @@ static int resolv_send_query(struct resolv_resolution 
*resolution)
        }
 
        list_for_each_entry(ns, &resolvers->nameservers, list) {
-               if (dns_send_nameserver(ns, trash.area, len) >= 0)
+               enum dns_server_type type;
+
+               type = ns->dgram ? DNS_SERVER_DGRAM : DNS_SERVER_STREAM;
+               if (dns_send_nameserver(ns, type, trash.area, len) >= 0)
                        resolution->nb_queries++;
        }
 
@@ -2313,14 +2316,14 @@ void resolv_unlink_resolution(struct resolv_requester 
*requester)
        leave_resolver_code();
 }
 
-/* Called when a network IO is generated on a name server socket for an 
incoming
- * packet. It performs the following actions:
+/* Called when a network IO is generated on server type <type> of nameserver
+ * <ns> for an incoming packet. It performs the following actions:
  *  - check if the packet requires processing (not outdated resolution)
  *  - ensure the DNS packet received is valid and call requester's callback
  *  - call requester's error callback if invalid response
  *  - check the dn_name in the packet against the one sent
  */
-static int resolv_process_responses(struct dns_nameserver *ns)
+static int resolv_process_responses(struct dns_nameserver *ns, enum 
dns_server_type type)
 {
        struct dns_counters   *tmpcounters;
        struct resolvers  *resolvers;
@@ -2341,9 +2344,9 @@ static int resolv_process_responses(struct dns_nameserver 
*ns)
        /* process all pending input messages */
        while (1) {
                /* read message received */
-               if ((buflen = dns_recv_nameserver(ns, (void *)buf, 
sizeof(buf))) <= 0) {
+               buflen = dns_recv_nameserver(ns, type, (void *)buf, 
sizeof(buf));
+               if (buflen <= 0)
                        break;
-               }
 
                /* message too big */
                if (buflen > resolvers->accepted_payload_size) {
-- 
2.55.0

Reply via email to