Hi Baptiste, Maxim,

On Wed, Dec 28, 2016 at 02:04:44PM +0100, Baptiste wrote:
> On Fri, Dec 23, 2016 at 5:21 PM, Willy Tarreau <w...@1wt.eu> wrote:
> > Regarding this issue, I think that in fact we should decide to split the
> > server port apart from the address. After all, we're manipulating the port
> > and the address separately everywhere, we even have some extra settings in
> > other places (eg the fact that the ports are relative). I have not yet
> > analysed the impact of all of this but I think that's definitely something
> > we need to consider for the mid term. It will also remove most of the
> > "switch (family)" needed to retrieve/manipulate ports.
(...)
> I tend to fully agree if you mean having a "service_port" parameter in the
> "struct server" (or some kind of)
> Each time we have to manipulate addr and/or port in the struct
> sockaddr_storage, it's a nightmare and we have to think about all the
> corner cases...

OK so I managed to do it and I think I got it working fine now. It took
some time because in order not to miss any place I renamed the struct
member so that I was sure to spot all places.

I found a small bug in the current DNS resolution implementation when the
family is set to AF_UNSPEC, it immediately marks it as invalid and tries
again, so my DNS server got flooded during my tests :-) But that's fixed
now.

Thus now str2sa_range() doesn't change the family if the address doesn't
resolved. It however continues to *also* copy the port into the address
in the case where it resolves so that we don't have to touch all other
call places (listeners, peers, source, etc). I could get this config to
resolve all addresses as expected :

  resolvers mydns
     nameserver dns1 8.8.8.8:53
     resolve_retries       3
     timeout retry         1s
     hold valid           1s

  defaults
     option httplog
     log 127.0.0.1:5514 local0
     mode    http
     timeout connect 5s
     timeout client  60s
     timeout server  90s

  frontend f
     bind *:8888
     #bind :::8888

  backend b
     # default-server resolvers mydns ## doesn't work
     server s1       127.0.0.1:8000 check
     server s2       127.0.0.2:8000 check disabled
     server s3       wtap.haproxy.local:8000 init-addr none check resolvers 
mydns
     server s4       haproxy.ipv6.1wt.eu:80 init-addr none check resolvers mydns
     server s5       www6.1wt.eu:80
     server s6       i...@www6.1wt.eu:80
     server s7       i...@www6.1wt.eu:80 init-addr libc
     server s8       1wt.eu:80 resolve-prefer ipv6 check init-addr none 
resolvers mydns
     server s9       1wt.eu:80 resolve-prefer ipv4 check

By the way I found that "resolvers" doesn't work in default-server AND
doesn't emit any warning so I had to specify it on each line. We need to
fix this before issuing 1.7.2.

I'd like you guys to take a look at the attached patches (rebased on 1.7).
There's also an all-in-one patch that you can apply to latest 1.7 snapshot
Maxim if you're interested.

For me it passes all tests and seems to be OK now.

Barring any objection, I'll merge all of them into 1.7 and will make a note
for distro maintainers to properly pick them or they'll get annoying bug
reports.

Thanks,
Willy
>From c5ffce6f998945c1c477387da9908d408b464622 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w...@1wt.eu>
Date: Fri, 6 Jan 2017 17:41:29 +0100
Subject: MEDIUM: server: split the address and the port into two different
 fields
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4

Keeping the address and the port in the same field causes a lot of problems,
specifically on the DNS part where we're forced to cheat on the family to be
able to keep the port. This causes some issues such as some families not being
resolvable anymore.

This patch first moves the service port to a new field "svc_port" so that the
port field is never used anymore in the "addr" field (struct sockaddr_storage).
All call places were adapted (there aren't that many).
---
 include/types/server.h |  3 ++-
 src/backend.c          | 21 +++++++++++++--------
 src/checks.c           | 14 +++++++++++---
 src/server.c           |  5 +++--
 src/stats.c            |  4 ++--
 5 files changed, 31 insertions(+), 16 deletions(-)

diff --git a/include/types/server.h b/include/types/server.h
index 20c314b..4678934 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -230,7 +230,8 @@ struct server {
 
        const struct netns_entry *netns;        /* contains network namespace 
name or NULL. Network namespace comes from configuration */
        /* warning, these structs are huge, keep them at the bottom */
-       struct sockaddr_storage addr;           /* the address to connect to */
+       struct sockaddr_storage addr;           /* the address to connect to, 
doesn't include the port */
+       unsigned int svc_port;                  /* the port to connect to (for 
relevant families) */
        struct xprt_ops *xprt;                  /* transport-layer operations */
        unsigned down_time;                     /* total time the server was 
down */
        time_t last_change;                     /* last time, when the state 
was changed */
diff --git a/src/backend.c b/src/backend.c
index efa9472..094c519 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -770,6 +770,7 @@ int assign_server_address(struct stream *s)
                        return SRV_STATUS_INTERNAL;
 
                srv_conn->addr.to = objt_server(s->target)->addr;
+               set_host_port(&srv_conn->addr.to, 
objt_server(s->target)->svc_port);
 
                if (!is_addr(&srv_conn->addr.to) && cli_conn) {
                        /* if the server has no address, we use the same address
@@ -1346,7 +1347,8 @@ int tcp_persist_rdp_cookie(struct stream *s, struct 
channel *req, int an_bit)
        int              ret;
        struct sample    smp;
        struct server *srv = px->srv;
-       struct sockaddr_in addr;
+       uint16_t port;
+       uint32_t addr;
        char *p;
 
        DPRINTF(stderr,"[%u] %s: stream=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%d 
analysers=%02x\n",
@@ -1367,22 +1369,25 @@ int tcp_persist_rdp_cookie(struct stream *s, struct 
channel *req, int an_bit)
        if (ret == 0 || (smp.flags & SMP_F_MAY_CHANGE) || smp.data.u.str.len == 
0)
                goto no_cookie;
 
-       memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-
-       /* Considering an rdp cookie detected using acl, str ended with 
<cr><lf> and should return */
-       addr.sin_addr.s_addr = strtoul(smp.data.u.str.str, &p, 10);
+       /* Considering an rdp cookie detected using acl, str ended with 
<cr><lf> and should return.
+        * The cookie format is <ip> "." <port> where "ip" is the integer 
corresponding to the
+        * server's IP address in network order, and "port" is the integer 
corresponding to the
+        * server's port in network order. Comments please Emeric.
+        */
+       addr = strtoul(smp.data.u.str.str, &p, 10);
        if (*p != '.')
                goto no_cookie;
        p++;
-       addr.sin_port = (unsigned short)strtoul(p, &p, 10);
+
+       port = ntohs(strtoul(p, &p, 10));
        if (*p != '.')
                goto no_cookie;
 
        s->target = NULL;
        while (srv) {
                if (srv->addr.ss_family == AF_INET &&
-                   memcmp(&addr, &(srv->addr), sizeof(addr)) == 0) {
+                   port == srv->svc_port &&
+                   addr == ((struct sockaddr_in 
*)&srv->addr)->sin_addr.s_addr) {
                        if ((srv->state != SRV_ST_STOPPED) || (px->options & 
PR_O_PERSIST)) {
                                /* we found the server and it is usable */
                                s->flags |= SF_DIRECT | SF_ASSIGNED;
diff --git a/src/checks.c b/src/checks.c
index 8eb2c7a..53513ca 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -533,7 +533,10 @@ static int httpchk_build_status_header(struct server *s, 
char *buffer, int size)
                             (s->state != SRV_ST_STOPPED) ? (s->check.fall) : 
(s->check.rise));
 
        addr_to_str(&s->addr, addr, sizeof(addr));
-       port_to_str(&s->addr, port, sizeof(port));
+       if (s->addr.ss_family == AF_INET || s->addr.ss_family == AF_INET6)
+               snprintf(port, sizeof(port), "%u", s->svc_port);
+       else
+               *port = 0;
 
        hlen += snprintf(buffer + hlen,  size - hlen, "; address=%s; port=%s; 
name=%s/%s; node=%s; weight=%d/%d; scur=%d/%d; qcur=%d",
                             addr, port, s->proxy->id, s->id,
@@ -1784,7 +1787,11 @@ static int prepare_external_check(struct check *check)
 
        addr_to_str(&s->addr, buf, sizeof(buf));
        check->argv[3] = strdup(buf);
-       port_to_str(&s->addr, buf, sizeof(buf));
+
+       if (s->addr.ss_family == AF_INET || s->addr.ss_family == AF_INET6)
+               snprintf(buf, sizeof(buf), "%u", s->svc_port);
+       else
+               *buf = 0;
        check->argv[4] = strdup(buf);
 
        for (i = 0; i < 5; i++) {
@@ -3448,7 +3455,8 @@ int srv_check_healthcheck_port(struct check *chk)
         */
        if (srv->flags & SRV_F_MAPPORTS)
                return 0;
-       i = get_host_port(&srv->addr); /* by default */
+
+       i = srv->svc_port; /* by default */
        if (i > 0)
                return i;
 
diff --git a/src/server.c b/src/server.c
index 08cc9cd..109663c 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1063,6 +1063,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
 
  skip_name_resolution:
                        newsrv->addr = *sk;
+                       newsrv->svc_port = get_host_port(sk);
                        newsrv->xprt  = newsrv->check.xprt = newsrv->agent.xprt 
= &raw_sock;
 
                        if (!protocol_by_family(newsrv->addr.ss_family)) {
@@ -2810,7 +2811,7 @@ const char *update_server_addr_port(struct server *s, 
const char *addr, const ch
                        chunk_appendf(msg, ", ");
 
                /* collecting data currently setup */
-               current_port = get_host_port(&s->addr);
+               current_port = s->svc_port;
 
                /* check if PORT change is required */
                port_change_required = 0;
@@ -2851,7 +2852,7 @@ const char *update_server_addr_port(struct server *s, 
const char *addr, const ch
                /* applying PORT changes if required and update response 
message */
                if (port_change_required) {
                        /* apply new port */
-                       set_host_port(&s->addr, new_port);
+                       s->svc_port = new_port;
 
                        /* prepare message */
                        chunk_appendf(msg, "port changed from '");
diff --git a/src/stats.c b/src/stats.c
index 52dcfe8..60b3756 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -1445,11 +1445,11 @@ int stats_fill_sv_stats(struct proxy *px, struct server 
*sv, int flags,
                switch (addr_to_str(&sv->addr, str, sizeof(str))) {
                case AF_INET:
                        stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, 
chunk_newstr(out));
-                       chunk_appendf(out, "%s:%d", str, 
get_host_port(&sv->addr));
+                       chunk_appendf(out, "%s:%d", str, sv->svc_port);
                        break;
                case AF_INET6:
                        stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, 
chunk_newstr(out));
-                       chunk_appendf(out, "[%s]:%d", str, 
get_host_port(&sv->addr));
+                       chunk_appendf(out, "[%s]:%d", str, sv->svc_port);
                        break;
                case AF_UNIX:
                        stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, 
"unix");
-- 
1.7.12.1

>From 2218b6380256fb3ca9e329c269f00b8846ca5935 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w...@1wt.eu>
Date: Fri, 6 Jan 2017 18:32:38 +0100
Subject: MINOR: tools: make str2sa_range() return the port in a separate
 argument
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4

This will be needed so that we're don't have to extract it from the
returned address where it will not always be anymore (eg: for unresolved
servers).
---
 include/common/standard.h |  5 ++++-
 src/cfgparse.c            | 18 +++++++++---------
 src/hlua.c                |  2 +-
 src/server.c              |  8 ++++----
 src/standard.c            |  4 +++-
 5 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/include/common/standard.h b/include/common/standard.h
index e16b304..87f90a6 100644
--- a/include/common/standard.h
+++ b/include/common/standard.h
@@ -279,7 +279,10 @@ extern const char *invalid_domainchar(const char *name);
  * address (typically the path to a unix socket). If use_dns is not true,
  * the funtion cannot accept the DNS resolution.
  */
-struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, 
char **err, const char *pfx, char **fqdn, int use_dns);
+struct sockaddr_storage *str2sa_range(const char *str,
+                                      int *port, int *low, int *high,
+                                      char **err, const char *pfx,
+                                      char **fqdn, int resolve);
 
 /* converts <str> to a struct in_addr containing a network mask. It can be
  * passed in dotted form (255.255.255.0) or in CIDR form (24). It returns 1
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 0ffc74d..db8feeb 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -243,7 +243,7 @@ int str2listener(char *str, struct proxy *curproxy, struct 
bind_conf *bind_conf,
                        *next++ = 0;
                }
 
-               ss2 = str2sa_range(str, &port, &end, err,
+               ss2 = str2sa_range(str, NULL, &port, &end, err,
                                   curproxy == global.stats_fe ? NULL : 
global.unix_bind.prefix,
                                   NULL, 1);
                if (!ss2)
@@ -1651,7 +1651,7 @@ int cfg_parse_global(const char *file, int linenum, char 
**args, int kwm)
                        }
                }
 
-               sk = str2sa_range(args[1], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s': %s\n", file, linenum, 
args[0], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -2180,7 +2180,7 @@ int cfg_parse_peers(const char *file, int linenum, char 
**args, int kwm)
                newpeer->last_change = now.tv_sec;
                newpeer->id = strdup(args[1]);
 
-               sk = str2sa_range(args[2], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[2], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s %s' : %s\n", file, 
linenum, args[0], args[1], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -2394,7 +2394,7 @@ int cfg_parse_resolvers(const char *file, int linenum, 
char **args, int kwm)
                newnameserver->conf.line = linenum;
                newnameserver->id = strdup(args[1]);
 
-               sk = str2sa_range(args[2], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[2], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s %s' : %s\n", file, 
linenum, args[0], args[1], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -2610,7 +2610,7 @@ int cfg_parse_mailers(const char *file, int linenum, char 
**args, int kwm)
 
                newmailer->id = strdup(args[1]);
 
-               sk = str2sa_range(args[2], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[2], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s %s' : %s\n", file, 
linenum, args[0], args[1], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -5874,7 +5874,7 @@ stats_error_parsing:
                else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, 
args[0], NULL))
                        err_code |= ERR_WARN;
 
-               sk = str2sa_range(args[1], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, 
args[0], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -6204,7 +6204,7 @@ stats_error_parsing:
                                }
                        }
 
-                       sk = str2sa_range(args[1], &port1, &port2, &errmsg, 
NULL, NULL, 1);
+                       sk = str2sa_range(args[1], NULL, &port1, &port2, 
&errmsg, NULL, NULL, 1);
                        if (!sk) {
                                Alert("parsing [%s:%d] : '%s': %s\n", file, 
linenum, args[0], errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -6256,7 +6256,7 @@ stats_error_parsing:
                curproxy->conn_src.iface_name = NULL;
                curproxy->conn_src.iface_len = 0;
 
-               sk = str2sa_range(args[1], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s %s' : %s\n",
                              file, linenum, args[0], args[1], errmsg);
@@ -6341,7 +6341,7 @@ stats_error_parsing:
                                } else {
                                        struct sockaddr_storage *sk;
 
-                                       sk = str2sa_range(args[cur_arg + 1], 
&port1, &port2, &errmsg, NULL, NULL, 1);
+                                       sk = str2sa_range(args[cur_arg + 1], 
NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
                                        if (!sk) {
                                                Alert("parsing [%s:%d] : '%s 
%s' : %s\n",
                                                      file, linenum, 
args[cur_arg], args[cur_arg+1], errmsg);
diff --git a/src/hlua.c b/src/hlua.c
index 1f28b46..1337566 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -2189,7 +2189,7 @@ __LJMP static int hlua_socket_connect(struct lua_State *L)
        conn->target = socket->s->target;
 
        /* Parse ip address. */
-       addr = str2sa_range(ip, &low, &high, NULL, NULL, NULL, 0);
+       addr = str2sa_range(ip, NULL, &low, &high, NULL, NULL, NULL, 0);
        if (!addr)
                WILL_LJMP(luaL_error(L, "connect: cannot parse destination 
address '%s'", ip));
        if (low != high)
diff --git a/src/server.c b/src/server.c
index 109663c..34a838b 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1006,7 +1006,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                         *  - IP:+N => port=+N, relative
                         *  - IP:-N => port=-N, relative
                         */
-                       sk = str2sa_range(args[2], &port1, &port2, &errmsg, 
NULL, &fqdn, 0);
+                       sk = str2sa_range(args[2], NULL, &port1, &port2, 
&errmsg, NULL, &fqdn, 0);
                        if (!sk) {
                                Alert("parsing [%s:%d] : '%s %s' : %s\n", file, 
linenum, args[0], args[1], errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -1394,7 +1394,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                                int port1, port2;
                                struct protocol *proto;
 
-                               sk = str2sa_range(args[cur_arg + 1], &port1, 
&port2, &errmsg, NULL, NULL, 1);
+                               sk = str2sa_range(args[cur_arg + 1], NULL, 
&port1, &port2, &errmsg, NULL, NULL, 1);
                                if (!sk) {
                                        Alert("parsing [%s:%d] : '%s' : %s\n",
                                              file, linenum, args[cur_arg], 
errmsg);
@@ -1606,7 +1606,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                                }
 
                                newsrv->conn_src.opts |= CO_SRC_BIND;
-                               sk = str2sa_range(args[cur_arg + 1], &port_low, 
&port_high, &errmsg, NULL, NULL, 1);
+                               sk = str2sa_range(args[cur_arg + 1], NULL, 
&port_low, &port_high, &errmsg, NULL, NULL, 1);
                                if (!sk) {
                                        Alert("parsing [%s:%d] : '%s %s' : 
%s\n",
                                              file, linenum, args[cur_arg], 
args[cur_arg+1], errmsg);
@@ -1706,7 +1706,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                                                        struct sockaddr_storage 
*sk;
                                                        int port1, port2;
 
-                                                       sk = 
str2sa_range(args[cur_arg + 1], &port1, &port2, &errmsg, NULL, NULL, 1);
+                                                       sk = 
str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
                                                        if (!sk) {
                                                                Alert("parsing 
[%s:%d] : '%s %s' : %s\n",
                                                                      file, 
linenum, args[cur_arg], args[cur_arg+1], errmsg);
diff --git a/src/standard.c b/src/standard.c
index 5a8f493..f4e50ed 100644
--- a/src/standard.c
+++ b/src/standard.c
@@ -816,7 +816,7 @@ struct sockaddr_storage *str2ip2(const char *str, struct 
sockaddr_storage *sa, i
  * When a file descriptor is passed, its value is put into the s_addr part of
  * the address when cast to sockaddr_in and the address family is AF_UNSPEC.
  */
-struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, 
char **err, const char *pfx, char **fqdn, int resolve)
+struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, 
int *high, char **err, const char *pfx, char **fqdn, int resolve)
 {
        static struct sockaddr_storage ss;
        struct sockaddr_storage *ret = NULL;
@@ -983,6 +983,8 @@ struct sockaddr_storage *str2sa_range(const char *str, int 
*low, int *high, char
 
        ret = &ss;
  out:
+       if (port)
+               *port = porta;
        if (low)
                *low = portl;
        if (high)
-- 
1.7.12.1

>From 1aff57565fbaaca648725d5c40ceece09b0c0336 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w...@1wt.eu>
Date: Fri, 6 Jan 2017 18:36:06 +0100
Subject: MINOR: server: take the destination port from the port field, not
 the addr
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4

Next patch will cause the port to disappear from the address field when servers
do not resolve so we need to take it from the separate field provided by
str2sa_range().
---
 src/server.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/server.c b/src/server.c
index 34a838b..3957b75 100644
--- a/src/server.c
+++ b/src/server.c
@@ -968,7 +968,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
 
                if (!defsrv) {
                        struct sockaddr_storage *sk;
-                       int port1, port2;
+                       int port1, port2, port;
                        struct protocol *proto;
                        struct dns_resolution *curr_resolution;
 
@@ -1006,7 +1006,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                         *  - IP:+N => port=+N, relative
                         *  - IP:-N => port=-N, relative
                         */
-                       sk = str2sa_range(args[2], NULL, &port1, &port2, 
&errmsg, NULL, &fqdn, 0);
+                       sk = str2sa_range(args[2], &port, &port1, &port2, 
&errmsg, NULL, &fqdn, 0);
                        if (!sk) {
                                Alert("parsing [%s:%d] : '%s %s' : %s\n", file, 
linenum, args[0], args[1], errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -1063,7 +1063,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
 
  skip_name_resolution:
                        newsrv->addr = *sk;
-                       newsrv->svc_port = get_host_port(sk);
+                       newsrv->svc_port = port;
                        newsrv->xprt  = newsrv->check.xprt = newsrv->agent.xprt 
= &raw_sock;
 
                        if (!protocol_by_family(newsrv->addr.ss_family)) {
-- 
1.7.12.1

>From 54c16020378f18b9ad58fbffc287389123641b4f Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w...@1wt.eu>
Date: Fri, 6 Jan 2017 18:42:57 +0100
Subject: MEDIUM: server: disable protocol validations when the server doesn't
 resolve
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4

When a server doesn't resolve we don't know the address family so we
can't perform the basic protocol validations. However we know that we'll
ultimately resolve to AF_INET4 or AF_INET6 so the controls are OK. It is
important to proceed like this otherwise it will not be possible to start
with unresolved addresses.
---
 src/server.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/server.c b/src/server.c
index 3957b75..71cf249 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1014,7 +1014,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                        }
 
                        proto = protocol_by_family(sk->ss_family);
-                       if (!proto || !proto->connect) {
+                       if (!fqdn && (!proto || !proto->connect)) {
                                Alert("parsing [%s:%d] : '%s %s' : connect() 
not supported for this address family.\n",
                                      file, linenum, args[0], args[1]);
                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -1066,7 +1066,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                        newsrv->svc_port = port;
                        newsrv->xprt  = newsrv->check.xprt = newsrv->agent.xprt 
= &raw_sock;
 
-                       if (!protocol_by_family(newsrv->addr.ss_family)) {
+                       if (!newsrv->hostname && 
!protocol_by_family(newsrv->addr.ss_family)) {
                                Alert("parsing [%s:%d] : Unknown protocol 
family %d '%s'\n",
                                      file, linenum, newsrv->addr.ss_family, 
args[2]);
                                err_code |= ERR_ALERT | ERR_FATAL;
-- 
1.7.12.1

>From 3287b59b15e7f188974a86c72fd677505b22c833 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w...@1wt.eu>
Date: Fri, 6 Jan 2017 19:23:20 +0100
Subject: BUG/MEDIUM: tools: do not force an unresolved address to
 AF_INET:0.0.0.0
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4

This prevents DNS from resolving IPv6-only servers in 1.7. Note, this
patch depends on the previous series :

  1. BUG/MINOR: tools: fix off-by-one in port size check
  2. BUG/MEDIUM: server: consider AF_UNSPEC as a valid address family
  3. WIP/MEDIUM: server: split the address and the port into two different 
fields
  4. WIP/MINOR: tools: make str2sa_range() return the port in a separate 
argument
  5. WIP/MINOR: server: take the destination port from the port field, not the 
addr
  6. MEDIUM: server: disable protocol validations when the server doesn't 
resolve

This fix (hence the whole series) must be backported to 1.7.
---
 src/standard.c | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/src/standard.c b/src/standard.c
index f4e50ed..8df1da6 100644
--- a/src/standard.c
+++ b/src/standard.c
@@ -958,14 +958,7 @@ struct sockaddr_storage *str2sa_range(const char *str, int 
*port, int *low, int
                 * set or if resolve is set, otherwise it's an error.
                 */
                if (str2ip2(str2, &ss, 0) == NULL) {
-                       if (!resolve && fqdn) {
-                               /* we'll still want to store the port, so let's
-                                * force it to IPv4 for now.
-                                */
-                               memset(&ss, 0, sizeof(ss));
-                               ss.ss_family = AF_INET;
-                       }
-                       else if ((!resolve && !fqdn) ||
+                       if ((!resolve && !fqdn) ||
                                 (resolve && str2ip2(str2, &ss, 1) == NULL)) {
                                memprintf(err, "invalid address: '%s' in 
'%s'\n", str2, str);
                                goto out;
-- 
1.7.12.1

diff --git a/include/common/standard.h b/include/common/standard.h
index e16b304..87f90a6 100644
--- a/include/common/standard.h
+++ b/include/common/standard.h
@@ -279,7 +279,10 @@ extern const char *invalid_domainchar(const char *name);
  * address (typically the path to a unix socket). If use_dns is not true,
  * the funtion cannot accept the DNS resolution.
  */
-struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, 
char **err, const char *pfx, char **fqdn, int use_dns);
+struct sockaddr_storage *str2sa_range(const char *str,
+                                      int *port, int *low, int *high,
+                                      char **err, const char *pfx,
+                                      char **fqdn, int resolve);
 
 /* converts <str> to a struct in_addr containing a network mask. It can be
  * passed in dotted form (255.255.255.0) or in CIDR form (24). It returns 1
diff --git a/include/types/server.h b/include/types/server.h
index 20c314b..4678934 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -230,7 +230,8 @@ struct server {
 
        const struct netns_entry *netns;        /* contains network namespace 
name or NULL. Network namespace comes from configuration */
        /* warning, these structs are huge, keep them at the bottom */
-       struct sockaddr_storage addr;           /* the address to connect to */
+       struct sockaddr_storage addr;           /* the address to connect to, 
doesn't include the port */
+       unsigned int svc_port;                  /* the port to connect to (for 
relevant families) */
        struct xprt_ops *xprt;                  /* transport-layer operations */
        unsigned down_time;                     /* total time the server was 
down */
        time_t last_change;                     /* last time, when the state 
was changed */
diff --git a/src/backend.c b/src/backend.c
index efa9472..094c519 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -770,6 +770,7 @@ int assign_server_address(struct stream *s)
                        return SRV_STATUS_INTERNAL;
 
                srv_conn->addr.to = objt_server(s->target)->addr;
+               set_host_port(&srv_conn->addr.to, 
objt_server(s->target)->svc_port);
 
                if (!is_addr(&srv_conn->addr.to) && cli_conn) {
                        /* if the server has no address, we use the same address
@@ -1346,7 +1347,8 @@ int tcp_persist_rdp_cookie(struct stream *s, struct 
channel *req, int an_bit)
        int              ret;
        struct sample    smp;
        struct server *srv = px->srv;
-       struct sockaddr_in addr;
+       uint16_t port;
+       uint32_t addr;
        char *p;
 
        DPRINTF(stderr,"[%u] %s: stream=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%d 
analysers=%02x\n",
@@ -1367,22 +1369,25 @@ int tcp_persist_rdp_cookie(struct stream *s, struct 
channel *req, int an_bit)
        if (ret == 0 || (smp.flags & SMP_F_MAY_CHANGE) || smp.data.u.str.len == 
0)
                goto no_cookie;
 
-       memset(&addr, 0, sizeof(addr));
-       addr.sin_family = AF_INET;
-
-       /* Considering an rdp cookie detected using acl, str ended with 
<cr><lf> and should return */
-       addr.sin_addr.s_addr = strtoul(smp.data.u.str.str, &p, 10);
+       /* Considering an rdp cookie detected using acl, str ended with 
<cr><lf> and should return.
+        * The cookie format is <ip> "." <port> where "ip" is the integer 
corresponding to the
+        * server's IP address in network order, and "port" is the integer 
corresponding to the
+        * server's port in network order. Comments please Emeric.
+        */
+       addr = strtoul(smp.data.u.str.str, &p, 10);
        if (*p != '.')
                goto no_cookie;
        p++;
-       addr.sin_port = (unsigned short)strtoul(p, &p, 10);
+
+       port = ntohs(strtoul(p, &p, 10));
        if (*p != '.')
                goto no_cookie;
 
        s->target = NULL;
        while (srv) {
                if (srv->addr.ss_family == AF_INET &&
-                   memcmp(&addr, &(srv->addr), sizeof(addr)) == 0) {
+                   port == srv->svc_port &&
+                   addr == ((struct sockaddr_in 
*)&srv->addr)->sin_addr.s_addr) {
                        if ((srv->state != SRV_ST_STOPPED) || (px->options & 
PR_O_PERSIST)) {
                                /* we found the server and it is usable */
                                s->flags |= SF_DIRECT | SF_ASSIGNED;
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 0ffc74d..db8feeb 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -243,7 +243,7 @@ int str2listener(char *str, struct proxy *curproxy, struct 
bind_conf *bind_conf,
                        *next++ = 0;
                }
 
-               ss2 = str2sa_range(str, &port, &end, err,
+               ss2 = str2sa_range(str, NULL, &port, &end, err,
                                   curproxy == global.stats_fe ? NULL : 
global.unix_bind.prefix,
                                   NULL, 1);
                if (!ss2)
@@ -1651,7 +1651,7 @@ int cfg_parse_global(const char *file, int linenum, char 
**args, int kwm)
                        }
                }
 
-               sk = str2sa_range(args[1], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s': %s\n", file, linenum, 
args[0], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -2180,7 +2180,7 @@ int cfg_parse_peers(const char *file, int linenum, char 
**args, int kwm)
                newpeer->last_change = now.tv_sec;
                newpeer->id = strdup(args[1]);
 
-               sk = str2sa_range(args[2], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[2], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s %s' : %s\n", file, 
linenum, args[0], args[1], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -2394,7 +2394,7 @@ int cfg_parse_resolvers(const char *file, int linenum, 
char **args, int kwm)
                newnameserver->conf.line = linenum;
                newnameserver->id = strdup(args[1]);
 
-               sk = str2sa_range(args[2], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[2], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s %s' : %s\n", file, 
linenum, args[0], args[1], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -2610,7 +2610,7 @@ int cfg_parse_mailers(const char *file, int linenum, char 
**args, int kwm)
 
                newmailer->id = strdup(args[1]);
 
-               sk = str2sa_range(args[2], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[2], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s %s' : %s\n", file, 
linenum, args[0], args[1], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -5874,7 +5874,7 @@ stats_error_parsing:
                else if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, 
args[0], NULL))
                        err_code |= ERR_WARN;
 
-               sk = str2sa_range(args[1], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s' : %s\n", file, linenum, 
args[0], errmsg);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -6204,7 +6204,7 @@ stats_error_parsing:
                                }
                        }
 
-                       sk = str2sa_range(args[1], &port1, &port2, &errmsg, 
NULL, NULL, 1);
+                       sk = str2sa_range(args[1], NULL, &port1, &port2, 
&errmsg, NULL, NULL, 1);
                        if (!sk) {
                                Alert("parsing [%s:%d] : '%s': %s\n", file, 
linenum, args[0], errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -6256,7 +6256,7 @@ stats_error_parsing:
                curproxy->conn_src.iface_name = NULL;
                curproxy->conn_src.iface_len = 0;
 
-               sk = str2sa_range(args[1], &port1, &port2, &errmsg, NULL, NULL, 
1);
+               sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, 
NULL, 1);
                if (!sk) {
                        Alert("parsing [%s:%d] : '%s %s' : %s\n",
                              file, linenum, args[0], args[1], errmsg);
@@ -6341,7 +6341,7 @@ stats_error_parsing:
                                } else {
                                        struct sockaddr_storage *sk;
 
-                                       sk = str2sa_range(args[cur_arg + 1], 
&port1, &port2, &errmsg, NULL, NULL, 1);
+                                       sk = str2sa_range(args[cur_arg + 1], 
NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
                                        if (!sk) {
                                                Alert("parsing [%s:%d] : '%s 
%s' : %s\n",
                                                      file, linenum, 
args[cur_arg], args[cur_arg+1], errmsg);
diff --git a/src/checks.c b/src/checks.c
index 8eb2c7a..53513ca 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -533,7 +533,10 @@ static int httpchk_build_status_header(struct server *s, 
char *buffer, int size)
                             (s->state != SRV_ST_STOPPED) ? (s->check.fall) : 
(s->check.rise));
 
        addr_to_str(&s->addr, addr, sizeof(addr));
-       port_to_str(&s->addr, port, sizeof(port));
+       if (s->addr.ss_family == AF_INET || s->addr.ss_family == AF_INET6)
+               snprintf(port, sizeof(port), "%u", s->svc_port);
+       else
+               *port = 0;
 
        hlen += snprintf(buffer + hlen,  size - hlen, "; address=%s; port=%s; 
name=%s/%s; node=%s; weight=%d/%d; scur=%d/%d; qcur=%d",
                             addr, port, s->proxy->id, s->id,
@@ -1784,7 +1787,11 @@ static int prepare_external_check(struct check *check)
 
        addr_to_str(&s->addr, buf, sizeof(buf));
        check->argv[3] = strdup(buf);
-       port_to_str(&s->addr, buf, sizeof(buf));
+
+       if (s->addr.ss_family == AF_INET || s->addr.ss_family == AF_INET6)
+               snprintf(buf, sizeof(buf), "%u", s->svc_port);
+       else
+               *buf = 0;
        check->argv[4] = strdup(buf);
 
        for (i = 0; i < 5; i++) {
@@ -3448,7 +3455,8 @@ int srv_check_healthcheck_port(struct check *chk)
         */
        if (srv->flags & SRV_F_MAPPORTS)
                return 0;
-       i = get_host_port(&srv->addr); /* by default */
+
+       i = srv->svc_port; /* by default */
        if (i > 0)
                return i;
 
diff --git a/src/hlua.c b/src/hlua.c
index 1f28b46..1337566 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -2189,7 +2189,7 @@ __LJMP static int hlua_socket_connect(struct lua_State *L)
        conn->target = socket->s->target;
 
        /* Parse ip address. */
-       addr = str2sa_range(ip, &low, &high, NULL, NULL, NULL, 0);
+       addr = str2sa_range(ip, NULL, &low, &high, NULL, NULL, NULL, 0);
        if (!addr)
                WILL_LJMP(luaL_error(L, "connect: cannot parse destination 
address '%s'", ip));
        if (low != high)
diff --git a/src/server.c b/src/server.c
index 08cc9cd..71cf249 100644
--- a/src/server.c
+++ b/src/server.c
@@ -968,7 +968,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
 
                if (!defsrv) {
                        struct sockaddr_storage *sk;
-                       int port1, port2;
+                       int port1, port2, port;
                        struct protocol *proto;
                        struct dns_resolution *curr_resolution;
 
@@ -1006,7 +1006,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                         *  - IP:+N => port=+N, relative
                         *  - IP:-N => port=-N, relative
                         */
-                       sk = str2sa_range(args[2], &port1, &port2, &errmsg, 
NULL, &fqdn, 0);
+                       sk = str2sa_range(args[2], &port, &port1, &port2, 
&errmsg, NULL, &fqdn, 0);
                        if (!sk) {
                                Alert("parsing [%s:%d] : '%s %s' : %s\n", file, 
linenum, args[0], args[1], errmsg);
                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -1014,7 +1014,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                        }
 
                        proto = protocol_by_family(sk->ss_family);
-                       if (!proto || !proto->connect) {
+                       if (!fqdn && (!proto || !proto->connect)) {
                                Alert("parsing [%s:%d] : '%s %s' : connect() 
not supported for this address family.\n",
                                      file, linenum, args[0], args[1]);
                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -1063,9 +1063,10 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
 
  skip_name_resolution:
                        newsrv->addr = *sk;
+                       newsrv->svc_port = port;
                        newsrv->xprt  = newsrv->check.xprt = newsrv->agent.xprt 
= &raw_sock;
 
-                       if (!protocol_by_family(newsrv->addr.ss_family)) {
+                       if (!newsrv->hostname && 
!protocol_by_family(newsrv->addr.ss_family)) {
                                Alert("parsing [%s:%d] : Unknown protocol 
family %d '%s'\n",
                                      file, linenum, newsrv->addr.ss_family, 
args[2]);
                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -1393,7 +1394,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                                int port1, port2;
                                struct protocol *proto;
 
-                               sk = str2sa_range(args[cur_arg + 1], &port1, 
&port2, &errmsg, NULL, NULL, 1);
+                               sk = str2sa_range(args[cur_arg + 1], NULL, 
&port1, &port2, &errmsg, NULL, NULL, 1);
                                if (!sk) {
                                        Alert("parsing [%s:%d] : '%s' : %s\n",
                                              file, linenum, args[cur_arg], 
errmsg);
@@ -1605,7 +1606,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                                }
 
                                newsrv->conn_src.opts |= CO_SRC_BIND;
-                               sk = str2sa_range(args[cur_arg + 1], &port_low, 
&port_high, &errmsg, NULL, NULL, 1);
+                               sk = str2sa_range(args[cur_arg + 1], NULL, 
&port_low, &port_high, &errmsg, NULL, NULL, 1);
                                if (!sk) {
                                        Alert("parsing [%s:%d] : '%s %s' : 
%s\n",
                                              file, linenum, args[cur_arg], 
args[cur_arg+1], errmsg);
@@ -1705,7 +1706,7 @@ int parse_server(const char *file, int linenum, char 
**args, struct proxy *curpr
                                                        struct sockaddr_storage 
*sk;
                                                        int port1, port2;
 
-                                                       sk = 
str2sa_range(args[cur_arg + 1], &port1, &port2, &errmsg, NULL, NULL, 1);
+                                                       sk = 
str2sa_range(args[cur_arg + 1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1);
                                                        if (!sk) {
                                                                Alert("parsing 
[%s:%d] : '%s %s' : %s\n",
                                                                      file, 
linenum, args[cur_arg], args[cur_arg+1], errmsg);
@@ -2810,7 +2811,7 @@ const char *update_server_addr_port(struct server *s, 
const char *addr, const ch
                        chunk_appendf(msg, ", ");
 
                /* collecting data currently setup */
-               current_port = get_host_port(&s->addr);
+               current_port = s->svc_port;
 
                /* check if PORT change is required */
                port_change_required = 0;
@@ -2851,7 +2852,7 @@ const char *update_server_addr_port(struct server *s, 
const char *addr, const ch
                /* applying PORT changes if required and update response 
message */
                if (port_change_required) {
                        /* apply new port */
-                       set_host_port(&s->addr, new_port);
+                       s->svc_port = new_port;
 
                        /* prepare message */
                        chunk_appendf(msg, "port changed from '");
diff --git a/src/standard.c b/src/standard.c
index 5a8f493..8df1da6 100644
--- a/src/standard.c
+++ b/src/standard.c
@@ -816,7 +816,7 @@ struct sockaddr_storage *str2ip2(const char *str, struct 
sockaddr_storage *sa, i
  * When a file descriptor is passed, its value is put into the s_addr part of
  * the address when cast to sockaddr_in and the address family is AF_UNSPEC.
  */
-struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, 
char **err, const char *pfx, char **fqdn, int resolve)
+struct sockaddr_storage *str2sa_range(const char *str, int *port, int *low, 
int *high, char **err, const char *pfx, char **fqdn, int resolve)
 {
        static struct sockaddr_storage ss;
        struct sockaddr_storage *ret = NULL;
@@ -958,14 +958,7 @@ struct sockaddr_storage *str2sa_range(const char *str, int 
*low, int *high, char
                 * set or if resolve is set, otherwise it's an error.
                 */
                if (str2ip2(str2, &ss, 0) == NULL) {
-                       if (!resolve && fqdn) {
-                               /* we'll still want to store the port, so let's
-                                * force it to IPv4 for now.
-                                */
-                               memset(&ss, 0, sizeof(ss));
-                               ss.ss_family = AF_INET;
-                       }
-                       else if ((!resolve && !fqdn) ||
+                       if ((!resolve && !fqdn) ||
                                 (resolve && str2ip2(str2, &ss, 1) == NULL)) {
                                memprintf(err, "invalid address: '%s' in 
'%s'\n", str2, str);
                                goto out;
@@ -983,6 +976,8 @@ struct sockaddr_storage *str2sa_range(const char *str, int 
*low, int *high, char
 
        ret = &ss;
  out:
+       if (port)
+               *port = porta;
        if (low)
                *low = portl;
        if (high)
diff --git a/src/stats.c b/src/stats.c
index 52dcfe8..60b3756 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -1445,11 +1445,11 @@ int stats_fill_sv_stats(struct proxy *px, struct server 
*sv, int flags,
                switch (addr_to_str(&sv->addr, str, sizeof(str))) {
                case AF_INET:
                        stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, 
chunk_newstr(out));
-                       chunk_appendf(out, "%s:%d", str, 
get_host_port(&sv->addr));
+                       chunk_appendf(out, "%s:%d", str, sv->svc_port);
                        break;
                case AF_INET6:
                        stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, 
chunk_newstr(out));
-                       chunk_appendf(out, "[%s]:%d", str, 
get_host_port(&sv->addr));
+                       chunk_appendf(out, "[%s]:%d", str, sv->svc_port);
                        break;
                case AF_UNIX:
                        stats[ST_F_ADDR] = mkf_str(FO_CONFIG|FS_SERVICE, 
"unix");

Reply via email to