]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Use the same interface listening port discovery code for all needed
authorYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Tue, 21 Jan 2025 09:04:30 +0000 (10:04 +0100)
committerYorgos Thessalonikefs <yorgos@nlnetlabs.nl>
Tue, 21 Jan 2025 09:04:30 +0000 (10:04 +0100)
  protocols.
- Port to string only when needed before getaddrinfo().

doc/Changelog
doc/unbound.conf.5.in
services/listen_dnsport.c
smallapp/unbound-checkconf.c
util/config_file.c
util/config_file.h

index e7d8803aafc35b3cfe8cb304f015e5ddf1738f06..8c9591884efce4bfb65d81d4070e9e064e45c01c 100644 (file)
@@ -1,3 +1,8 @@
+21 January 2025: Yorgos
+       - Use the same interface listening port discovery code for all needed
+         protocols.
+       - Port to string only when needed before getaddrinfo().
+
 20 January 2025: Yorgos
        - Merge #1222: Unique DoT and DoH SSL contexts to allow for different
          ALPN.
index 84c842f558a6b986ad767dd32e58d085beda1692..c5240d53a9448631c31af0c10f855ba77d613b23 100644 (file)
@@ -716,7 +716,7 @@ and initial ACL (check if the proxy itself is denied/refused by configuration).
 The proxied address (if any) will then be used as the true client address and
 will be used where applicable for logging, ACL, DNSTAP, RPZ and IP ratelimiting.
 PROXYv2 is supported for UDP and TCP/TLS listening interfaces.
-There is no support for PROXYv2 on a DoH or DNSCrypt listening interface.
+There is no support for PROXYv2 on a DoH, DoQ or DNSCrypt listening interface.
 Can list multiple, each on a new statement.
 .TP
 .B quic\-port: \fI<number>
index 2c4b28abf4982c1f87dea9f99d95defed0145c29..2a6c6301cb197ccf6b864ca66a7585353f1f64c4 100644 (file)
@@ -1034,7 +1034,7 @@ err:
  * Create socket from getaddrinfo results
  */
 static int
-make_sock(int stype, const char* ifname, const char* port,
+make_sock(int stype, const char* ifname, int port,
        struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
        int* reuseport, int transparent, int tcp_mss, int nodelay, int freebind,
        int use_systemd, int dscp, struct unbound_socket* ub_sock,
@@ -1042,9 +1042,11 @@ make_sock(int stype, const char* ifname, const char* port,
 {
        struct addrinfo *res = NULL;
        int r, s, inuse, noproto;
+       char portbuf[32];
+       snprintf(portbuf, sizeof(portbuf), "%d", port);
        hints->ai_socktype = stype;
        *noip6 = 0;
-       if((r=getaddrinfo(ifname, port, hints, &res)) != 0 || !res) {
+       if((r=getaddrinfo(ifname, portbuf, hints, &res)) != 0 || !res) {
 #ifdef USE_WINSOCK
                if(r == EAI_NONAME && hints->ai_family == AF_INET6){
                        *noip6 = 1; /* 'Host not found' for IP6 on winXP */
@@ -1052,7 +1054,7 @@ make_sock(int stype, const char* ifname, const char* port,
                }
 #endif
                log_err("node %s:%s getaddrinfo: %s %s",
-                       ifname?ifname:"default", port, gai_strerror(r),
+                       ifname?ifname:"default", portbuf, gai_strerror(r),
 #ifdef EAI_SYSTEM
                        (r==EAI_SYSTEM?(char*)strerror(errno):"")
 #else
@@ -1106,7 +1108,7 @@ make_sock(int stype, const char* ifname, const char* port,
 
 /** make socket and first see if ifname contains port override info */
 static int
-make_sock_port(int stype, const char* ifname, const char* port,
+make_sock_port(int stype, const char* ifname, int port,
        struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
        int* reuseport, int transparent, int tcp_mss, int nodelay, int freebind,
        int use_systemd, int dscp, struct unbound_socket* ub_sock,
@@ -1115,23 +1117,22 @@ make_sock_port(int stype, const char* ifname, const char* port,
        char* s = strchr(ifname, '@');
        if(s) {
                /* override port with ifspec@port */
-               char p[16];
+               int port;
                char newif[128];
                if((size_t)(s-ifname) >= sizeof(newif)) {
                        log_err("ifname too long: %s", ifname);
                        *noip6 = 0;
                        return -1;
                }
-               if(strlen(s+1) >= sizeof(p)) {
-                       log_err("portnumber too long: %s", ifname);
+               port = atoi(s+1);
+               if(port < 0 || 0 == port || port > 65535) {
+                       log_err("invalid portnumber in interface: %s", ifname);
                        *noip6 = 0;
                        return -1;
                }
                (void)strlcpy(newif, ifname, sizeof(newif));
                newif[s-ifname] = 0;
-               (void)strlcpy(p, s+1, sizeof(p));
-               p[strlen(s+1)]=0;
-               return make_sock(stype, newif, p, hints, v6only, noip6, rcv,
+               return make_sock(stype, newif, port, hints, v6only, noip6, rcv,
                        snd, reuseport, transparent, tcp_mss, nodelay, freebind,
                        use_systemd, dscp, ub_sock, additional);
        }
@@ -1248,7 +1249,7 @@ set_recvpktinfo(int s, int family)
  * @param do_udp: if udp should be used.
  * @param do_tcp: if tcp should be used.
  * @param hints: for getaddrinfo. family and flags have to be set by caller.
- * @param port: Port number to use (as string).
+ * @param port: Port number to use.
  * @param list: list of open ports, appended to, changed to point to list head.
  * @param rcv: receive buffer size for UDP
  * @param snd: send buffer size for UDP
@@ -1274,7 +1275,7 @@ set_recvpktinfo(int s, int family)
  */
 static int
 ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
-       struct addrinfo *hints, const char* port, struct listen_port** list,
+       struct addrinfo *hints, int port, struct listen_port** list,
        size_t rcv, size_t snd, int ssl_port,
        struct config_strlist* tls_additional_port, int https_port,
        struct config_strlist* proxy_protocol_port,
@@ -1287,6 +1288,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
        int is_https = if_is_https(ifname, port, https_port);
        int is_dnscrypt = if_is_dnscrypt(ifname, port, dnscrypt_port);
        int is_pp2 = if_is_pp2(ifname, port, proxy_protocol_port);
+       int is_doq = if_is_quic(ifname, port, quic_port);
        /* Always set TCP_NODELAY on TLS connection as it speeds up the TLS
         * handshake. DoH had already such option so we respect it.
         * Otherwise the server waits before sending more handshake data for
@@ -1294,7 +1296,6 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
         * client waits for more data before ACKing (delayed ACK). */
        int nodelay = is_https?http2_nodelay:is_ssl; 
        struct unbound_socket* ub_sock;
-       int is_doq = if_is_quic(ifname, port, quic_port);
        const char* add = NULL;
 
        if(!do_udp && !do_tcp)
@@ -1358,13 +1359,11 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
                } else if(is_doq) {
                        udp_port_type = listen_type_doq;
                        add = "doq";
-                       if(((strchr(ifname, '@') &&
-                               atoi(strchr(ifname, '@')+1) == 53) ||
-                               (!strchr(ifname, '@') && atoi(port) == 53))) {
-                               log_err("DNS over QUIC is not allowed on "
-                                       "port 53. Port 53 is for DNS "
-                                       "datagrams. Error for "
-                                       "interface '%s'.", ifname);
+                       if(if_listens_on(ifname, port, 53, NULL)) {
+                               log_err("DNS over QUIC is strictly not "
+                                       "allowed on port 53 as per RFC 9250. "
+                                       "Port 53 is for DNS datagrams. Error "
+                                       "for interface '%s'.", ifname);
                                free(ub_sock->addr);
                                free(ub_sock);
                                return 0;
@@ -1412,8 +1411,6 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
                }
        }
        if(do_tcp) {
-               int is_ssl = if_is_ssl(ifname, port, ssl_port,
-                       tls_additional_port);
                enum listen_type port_type;
                ub_sock = calloc(1, sizeof(struct unbound_socket));
                if(!ub_sock)
@@ -1881,8 +1878,6 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
        struct addrinfo hints;
        int i, do_ip4, do_ip6;
        int do_tcp, do_auto;
-       char portbuf[32];
-       snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
        do_ip4 = cfg->do_ip4;
        do_ip6 = cfg->do_ip6;
        do_tcp = cfg->do_tcp;
@@ -1928,12 +1923,11 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
                                        return NULL;
                                }
                                now = after;
-                               snprintf(portbuf, sizeof(portbuf), "%d", extraport);
                                if(do_ip6) {
                                        hints.ai_family = AF_INET6;
                                        if(!ports_create_if("::0",
                                                do_auto, cfg->do_udp, do_tcp,
-                                               &hints, portbuf, &list,
+                                               &hints, extraport, &list,
                                                cfg->so_rcvbuf, cfg->so_sndbuf,
                                                cfg->ssl_port, cfg->tls_additional_port,
                                                cfg->https_port,
@@ -1952,7 +1946,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
                                        hints.ai_family = AF_INET;
                                        if(!ports_create_if("0.0.0.0",
                                                do_auto, cfg->do_udp, do_tcp,
-                                               &hints, portbuf, &list,
+                                               &hints, extraport, &list,
                                                cfg->so_rcvbuf, cfg->so_sndbuf,
                                                cfg->ssl_port, cfg->tls_additional_port,
                                                cfg->https_port,
@@ -1974,7 +1968,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
                        hints.ai_family = AF_INET6;
                        if(!ports_create_if(do_auto?"::0":"::1",
                                do_auto, cfg->do_udp, do_tcp,
-                               &hints, portbuf, &list,
+                               &hints, cfg->port, &list,
                                cfg->so_rcvbuf, cfg->so_sndbuf,
                                cfg->ssl_port, cfg->tls_additional_port,
                                cfg->https_port, cfg->proxy_protocol_port,
@@ -1992,7 +1986,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
                        hints.ai_family = AF_INET;
                        if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1",
                                do_auto, cfg->do_udp, do_tcp,
-                               &hints, portbuf, &list,
+                               &hints, cfg->port, &list,
                                cfg->so_rcvbuf, cfg->so_sndbuf,
                                cfg->ssl_port, cfg->tls_additional_port,
                                cfg->https_port, cfg->proxy_protocol_port,
@@ -2012,7 +2006,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
                                continue;
                        hints.ai_family = AF_INET6;
                        if(!ports_create_if(ifs[i], 0, cfg->do_udp,
-                               do_tcp, &hints, portbuf, &list,
+                               do_tcp, &hints, cfg->port, &list,
                                cfg->so_rcvbuf, cfg->so_sndbuf,
                                cfg->ssl_port, cfg->tls_additional_port,
                                cfg->https_port, cfg->proxy_protocol_port,
@@ -2030,7 +2024,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
                                continue;
                        hints.ai_family = AF_INET;
                        if(!ports_create_if(ifs[i], 0, cfg->do_udp,
-                               do_tcp, &hints, portbuf, &list,
+                               do_tcp, &hints, cfg->port, &list,
                                cfg->so_rcvbuf, cfg->so_sndbuf,
                                cfg->ssl_port, cfg->tls_additional_port,
                                cfg->https_port, cfg->proxy_protocol_port,
index 6cc5285ecf15bfcc795626a3bc51404096fcb1b7..3b7ba758afa5fb836991d8a38a1440b6aab16caf 100644 (file)
@@ -342,8 +342,6 @@ interfacechecks(struct config_file* cfg)
        int i, j, i2, j2;
        char*** resif = NULL;
        int* num_resif = NULL;
-       char portbuf[32];
-       snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
 
        if(cfg->num_ifs != 0) {
                resif = (char***)calloc(cfg->num_ifs, sizeof(char**));
@@ -366,15 +364,19 @@ interfacechecks(struct config_file* cfg)
                                cfg->ifs[i]);
                }
                /* check for port combinations that are not supported */
-               if(if_is_pp2(resif[i][0], portbuf, cfg->proxy_protocol_port)) {
-                       if(if_is_dnscrypt(resif[i][0], portbuf,
+               if(if_is_pp2(resif[i][0], cfg->port, cfg->proxy_protocol_port)) {
+                       if(if_is_dnscrypt(resif[i][0], cfg->port,
                                cfg->dnscrypt_port)) {
                                fatal_exit("PROXYv2 and DNSCrypt combination not "
                                        "supported!");
-                       } else if(if_is_https(resif[i][0], portbuf,
+                       } else if(if_is_https(resif[i][0], cfg->port,
                                cfg->https_port)) {
                                fatal_exit("PROXYv2 and DoH combination not "
                                        "supported!");
+                       } else if(if_is_quic(resif[i][0], cfg->port,
+                               cfg->quic_port)) {
+                               fatal_exit("PROXYv2 and DoQ combination not "
+                                       "supported!");
                        }
                }
                /* search for duplicates in the returned addresses */
index b1f0d874157b61fc3d1c336ffb71171575a66462..19327c5bead8414b06c5f02b5c18bd9d7a9da945 100644 (file)
@@ -2771,75 +2771,50 @@ int options_remote_is_address(struct config_file* cfg)
        return (cfg->control_ifs.first->str[0] != '/');
 }
 
-/** see if interface is https, its port number == the https port number */
 int
-if_is_https(const char* ifname, const char* port, int https_port)
+if_listens_on(const char* ifname, int default_port, int port,
+       struct config_strlist* additional_ports)
 {
+       struct config_strlist* s;
        char* p = strchr(ifname, '@');
-       if(!p && atoi(port) == https_port)
-               return 1;
-       if(p && atoi(p+1) == https_port)
-               return 1;
-       return 0;
-}
+       int if_port;
+       if(p) if_port = atoi(p+1);
+       else  if_port = default_port;
 
-/** see if config contains https turned on */
-int cfg_has_https(struct config_file* cfg)
-{
-       int i;
-       char portbuf[32];
-       snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
-       for(i = 0; i<cfg->num_ifs; i++) {
-               if(if_is_https(cfg->ifs[i], portbuf, cfg->https_port))
-                       return 1;
+       if(port && if_port == port) return 1;
+
+       for(s = additional_ports; s; s = s->next) {
+               if(if_port == atoi(s->str)) return 1;
        }
        return 0;
 }
 
-/** see if interface is ssl, its port number == the ssl port number */
 int
-if_is_ssl(const char* ifname, const char* port, int ssl_port,
+if_is_ssl(const char* ifname, int default_port, int ssl_port,
        struct config_strlist* tls_additional_port)
 {
-       struct config_strlist* s;
-       char* p = strchr(ifname, '@');
-       if(!p && atoi(port) == ssl_port)
-               return 1;
-       if(p && atoi(p+1) == ssl_port)
-               return 1;
-       for(s = tls_additional_port; s; s = s->next) {
-               if(p && atoi(p+1) == atoi(s->str))
-                       return 1;
-               if(!p && atoi(port) == atoi(s->str))
-                       return 1;
-       }
-       return 0;
+       return if_listens_on(ifname, default_port, ssl_port,
+               tls_additional_port);
 }
 
-/** see if interface is PROXYv2, its port number == the proxy port number */
 int
-if_is_pp2(const char* ifname, const char* port,
+if_is_pp2(const char* ifname, int default_port,
        struct config_strlist* proxy_protocol_port)
 {
-       struct config_strlist* s;
-       char* p = strchr(ifname, '@');
-       for(s = proxy_protocol_port; s; s = s->next) {
-               if(p && atoi(p+1) == atoi(s->str))
-                       return 1;
-               if(!p && atoi(port) == atoi(s->str))
-                       return 1;
-       }
-       return 0;
+       return if_listens_on(ifname, default_port, 0, proxy_protocol_port);
 }
 
-/** see if interface is DNSCRYPT, its port number == the dnscrypt port number */
 int
-if_is_dnscrypt(const char* ifname, const char* port, int dnscrypt_port)
+if_is_https(const char* ifname, int default_port, int https_port)
+{
+       return if_listens_on(ifname, default_port, https_port, NULL);
+}
+
+int
+if_is_dnscrypt(const char* ifname, int default_port, int dnscrypt_port)
 {
 #ifdef USE_DNSCRYPT
-       return ((strchr(ifname, '@') &&
-               atoi(strchr(ifname, '@')+1) == dnscrypt_port) ||
-               (!strchr(ifname, '@') && atoi(port) == dnscrypt_port));
+       return if_listens_on(ifname, default_port, dnscrypt_port, NULL);
 #else
        (void)ifname;
        (void)port;
@@ -2848,40 +2823,42 @@ if_is_dnscrypt(const char* ifname, const char* port, int dnscrypt_port)
 #endif
 }
 
-/** see if interface is quic, its port number == the quic port number */
 int
-if_is_quic(const char* ifname, const char* port, int quic_port)
+if_is_quic(const char* ifname, int default_port, int quic_port)
 {
-#ifndef HAVE_NGTCP2
+#ifdef HAVE_NGTCP2
+       return if_listens_on(ifname, default_port, quic_port, NULL);
+#else
        (void)ifname;
        (void)port;
        (void)quic_port;
        return 0;
-#else
-       char* p = strchr(ifname, '@');
-       if(!p && atoi(port) == quic_port)
-               return 1;
-       if(p && atoi(p+1) == quic_port)
-               return 1;
-       return 0;
 #endif
 }
 
-/** see if config contains quic turned on */
 int
-cfg_has_quic(struct config_file* cfg)
+cfg_has_https(struct config_file* cfg)
 {
-#ifndef HAVE_NGTCP2
-       (void)cfg;
+       int i;
+       for(i = 0; i<cfg->num_ifs; i++) {
+               if(if_is_https(cfg->ifs[i], cfg->port, cfg->https_port))
+                       return 1;
+       }
        return 0;
-#else
+}
+
+int
+cfg_has_quic(struct config_file* cfg)
+{
+#ifdef HAVE_NGTCP2
        int i;
-       char portbuf[32];
-       snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
        for(i = 0; i<cfg->num_ifs; i++) {
-               if(if_is_quic(cfg->ifs[i], portbuf, cfg->quic_port))
+               if(if_is_quic(cfg->ifs[i], cfg->port, cfg->quic_port))
                        return 1;
        }
        return 0;
+#else
+       (void)cfg;
+       return 0;
 #endif
 }
index 6f808b9605931715b9c1b716ee77a65b1ad998d4..70b106ab7a687c1b644437707acb5e0386511471 100644 (file)
@@ -1395,29 +1395,46 @@ void w_config_adjust_directory(struct config_file* cfg);
 /** debug option for unit tests. */
 extern int fake_dsa, fake_sha1;
 
-/** see if interface is https, its port number == the https port number */
-int if_is_https(const char* ifname, const char* port, int https_port);
-
-/**
- * Return true if the config contains settings that enable https.
- * @param cfg: config information.
- * @return true if https ports are used for server.
+/** Return true if interface will listen to specific port(s).
+ * @param ifname: the interface as configured in the configuration file.
+ * @param default_port: the default port to use as the interface port if ifname
+ *     does not include a port via the '@' notation.
+ * @param port: port to check for, if 0 it will not be checked.
+ * @param additional_ports: additional configured ports, if any (nonNULL) to
+ *     be checked against.
+ * @return true if one of (port, additional_ports) matches the interface port.
  */
-int cfg_has_https(struct config_file* cfg);
+int if_listens_on(const char* ifname, int default_port, int port,
+       struct config_strlist* additional_ports);
+
+/** see if interface will listen on https;
+ *  its port number == the https port number */
+int if_is_https(const char* ifname, int default_port, int https_port);
 
-/** see if interface is ssl, its port number == the ssl port number */
-int if_is_ssl(const char* ifname, const char* port, int ssl_port,
+/** see if interface will listen on ssl;
+ *  its port number == the ssl port number or any of the additional ports */
+int if_is_ssl(const char* ifname, int default_port, int ssl_port,
        struct config_strlist* tls_additional_port);
 
-/** see if interface is PROXYv2, its port number == the proxy port number */
-int if_is_pp2(const char* ifname, const char* port,
+/** see if interface will listen on PROXYv2;
+ *  its port number == any of the proxy ports number */
+int if_is_pp2(const char* ifname, int default_port,
        struct config_strlist* proxy_protocol_port);
 
-/** see if interface is DNSCRYPT, its port number == the dnscrypt port number */
-int if_is_dnscrypt(const char* ifname, const char* port, int dnscrypt_port);
+/** see if interface will listen on DNSCRYPT;
+ *  its port number == the dnscrypt port number */
+int if_is_dnscrypt(const char* ifname, int default_port, int dnscrypt_port);
 
-/** see if interface is quic, its port number == the quic port number */
-int if_is_quic(const char* ifname, const char* port, int quic_port);
+/** see if interface will listen on quic;
+ *  its port number == the quic port number */
+int if_is_quic(const char* ifname, int default_port, int quic_port);
+
+/**
+ * Return true if the config contains settings that enable https.
+ * @param cfg: config information.
+ * @return true if https ports are used for server.
+ */
+int cfg_has_https(struct config_file* cfg);
 
 /**
  * Return true if the config contains settings that enable quic.