]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: server: split the address and the port into two different fields
authorWilly Tarreau <w@1wt.eu>
Fri, 6 Jan 2017 16:41:29 +0000 (17:41 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 6 Jan 2017 18:29:33 +0000 (19:29 +0100)
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
src/backend.c
src/checks.c
src/server.c
src/stats.c

index 5092eb7df780c737be1ea7a0c0a5639be3bf16cd..8a6f72f7789ca49ad9d6eab99d8919a1dd3c8b9c 100644 (file)
@@ -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 */
index bf70ee18b11db30bcb3c83cef9e6c2fbfd07bb9e..c9bc3ed8b04fa01c78198dce1d5eb55db6cda2d3 100644 (file)
@@ -769,6 +769,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
@@ -1345,7 +1346,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",
@@ -1366,22 +1368,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;
index 2075e3fb721cb143c51788b842261f99348cad72..7d424226756537ab6313ff5004ed83a19b6fc059 100644 (file)
@@ -527,7 +527,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,
@@ -1778,7 +1781,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++) {
@@ -3437,7 +3444,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;
 
index 1551f7208e888ec03ecd1cb93777d911589595e1..8aaf2184233856987d50e04524784e187790671b 100644 (file)
@@ -1062,6 +1062,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 = xprt_get(XPRT_RAW);
 
                        if (!protocol_by_family(newsrv->addr.ss_family)) {
@@ -2807,7 +2808,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;
@@ -2848,7 +2849,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 '");
index b7d030351f168fcfcae3ad68f563e85f2383b068..6bb33e826f03fce9f6caed7bd97ac5e866781e17 100644 (file)
@@ -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");