]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] add internal support for IPv6 server addresses
authorDavid du Colombier <dducolombier@exceliance.fr>
Thu, 10 Mar 2011 21:26:24 +0000 (22:26 +0100)
committerWilly Tarreau <w@1wt.eu>
Sun, 13 Mar 2011 21:00:12 +0000 (22:00 +0100)
This patch turns internal server addresses to sockaddr_storage to
store IPv6 addresses, and makes the connect() function use it. This
code already works but some caveats with getaddrinfo/gethostbyname
still need to be sorted out while the changes had to be merged at
this stage of internal architecture changes. So for now the config
parser will not emit an IPv6 address yet so that user experience
remains unchanged.

This change should have absolutely zero user-visible effect, otherwise
it's a bug introduced during the merge, that should be reported ASAP.

14 files changed:
include/common/standard.h
include/proto/proto_tcp.h
include/types/peers.h
include/types/proxy.h
include/types/server.h
include/types/stream_interface.h
src/backend.c
src/cfgparse.c
src/checks.c
src/dumpstats.c
src/peers.c
src/proto_http.c
src/proto_tcp.c
src/standard.c

index 3990e6ffab2ad014d39de65bd67b0644e659dddc..712d941286a44992db302f59315e63bb8b589b6e 100644 (file)
@@ -158,7 +158,7 @@ struct sockaddr_un *str2sun(const char *str);
  * The format is "addr:port", where "addr" can be a dotted IPv4 address,
  * a host name, or empty or "*" to indicate INADDR_ANY.
  */
-struct sockaddr_in *str2sa(char *str);
+struct sockaddr_storage *str2sa(char *str);
 
 /*
  * converts <str> to a struct sockaddr_in* which is locally allocated, and a
@@ -169,7 +169,7 @@ struct sockaddr_in *str2sa(char *str);
  * "addr[:port[-port]]", where "addr" can be a dotted IPv4 address, a host
  * name, or empty or "*" to indicate INADDR_ANY.
  */
-struct sockaddr_in *str2sa_range(char *str, int *low, int *high);
+struct sockaddr_storage *str2sa_range(char *str, int *low, int *high);
 
 /* 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
@@ -188,12 +188,12 @@ int str2net(const char *str, struct in_addr *addr, struct in_addr *mask);
 /*
  * Parse IP address found in url.
  */
-int url2ip(const char *addr, struct in_addr *dst);
+int url2ipv4(const char *addr, struct in_addr *dst);
 
 /*
- * Resolve destination server from URL. Convert <str> to a sockaddr_in*.
+ * Resolve destination server from URL. Convert <str> to a sockaddr_storage*.
  */
-int url2sa(const char *url, int ulen, struct sockaddr_in *addr);
+int url2sa(const char *url, int ulen, struct sockaddr_storage *addr);
 
 /* will try to encode the string <string> replacing all characters tagged in
  * <map> with the hexadecimal representation of their ASCII-code (2 digits)
@@ -466,4 +466,22 @@ static inline unsigned int __full_hash(unsigned int a)
        return a * 3221225473U;
 }
 
+/* returns non-zero if addr has a valid and non-null IPv4 or IPv6 address,
+ * otherwise zero.
+ */
+static inline int is_addr(struct sockaddr_storage *addr)
+{
+       int i;
+
+       switch (addr->ss_family) {
+       case AF_INET:
+               return *(int *)&((struct sockaddr_in *)&addr)->sin_addr;
+       case AF_INET6:
+               for (i = 0; i < sizeof(struct in6_addr) / sizeof(int); i++)
+                       if (((int *)&((struct sockaddr_in6 *)addr)->sin6_addr)[i] != 0)
+                               return ((int *)&((struct sockaddr_in6 *)addr)->sin6_addr)[i];
+       }
+       return 0;
+}
+
 #endif /* _COMMON_STANDARD_H */
index b871003a45dd6ec2db33c47930255d6b2ff17319..26e06df8cc70d7d2879e460c1a249cce1eb71a09 100644 (file)
 #include <types/task.h>
 #include <proto/stick_table.h>
 
-int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote);
+int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct sockaddr_storage *remote);
 void tcpv4_add_listener(struct listener *listener);
 void tcpv6_add_listener(struct listener *listener);
-int tcpv4_connect_server(struct stream_interface *si);
+int tcp_connect_server(struct stream_interface *si);
 int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit);
 int tcp_inspect_response(struct session *s, struct buffer *rep, int an_bit);
 int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit);
index b5b92c2b77cae77ac72836407f6b4696b78567e0..24ab804b19822e17a2864a3ee254a1bfb108ae18 100644 (file)
@@ -72,7 +72,7 @@ struct peer {
                int line;         /* line where the section appears */
        } conf;                   /* config information */
        time_t last_change;
-       struct sockaddr_in addr;  /* peer address */
+       struct sockaddr_storage addr;  /* peer address */
        struct peer *next;        /* next peer in the list */
 };
 
index e724a25b43f533fcb5b8818c88ca81a3d9e4c55c..95736b183054dd0d592a30301217c7c83a3fa52c 100644 (file)
@@ -182,7 +182,7 @@ struct proxy {
        unsigned int fe_req_ana, be_req_ana;    /* bitmap of common request protocol analysers for the frontend and backend */
        unsigned int fe_rsp_ana, be_rsp_ana;    /* bitmap of common response protocol analysers for the frontend and backend */
        int mode;                               /* mode = PR_MODE_TCP, PR_MODE_HTTP or PR_MODE_HEALTH */
-       struct sockaddr_in dispatch_addr;       /* the default address to connect to */
+       struct sockaddr_storage dispatch_addr;  /* the default address to connect to */
        union {
                struct proxy *be;               /* default backend, or NULL if none set */
                char *name;                     /* default backend name during config parse */
@@ -271,9 +271,9 @@ struct proxy {
 
        int conn_retries;                       /* maximum number of connect retries */
        int cap;                                /* supported capabilities (PR_CAP_*) */
-       struct sockaddr_in source_addr;         /* the address to which we want to bind for connect() */
+       struct sockaddr_storage source_addr;    /* the address to which we want to bind for connect() */
 #if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
-       struct sockaddr_in tproxy_addr;         /* non-local address we want to bind to for connect() */
+       struct sockaddr_storage tproxy_addr;    /* non-local address we want to bind to for connect() */
        char *bind_hdr_name;                    /* bind to this header name if defined */
        int bind_hdr_len;                       /* length of the name of the header above */
        int bind_hdr_occ;                       /* occurrence number of header above: >0 = from first, <0 = from end, 0=disabled */
index 00251d8ec1e4bf71083571fed0974d87f8740506..c697457ea00766311efca73ca7d226609dc32208 100644 (file)
@@ -102,10 +102,10 @@ struct server {
        struct list pendconns;                  /* pending connections */
        struct task *check;                     /* the task associated to the health check processing */
 
-       struct sockaddr_in addr;                /* the address to connect to */
-       struct sockaddr_in source_addr;         /* the address to which we want to bind for connect() */
+       struct sockaddr_storage addr;           /* the address to connect to */
+       struct sockaddr_storage source_addr;    /* the address to which we want to bind for connect() */
 #if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
-       struct sockaddr_in tproxy_addr;         /* non-local address we want to bind to for connect() */
+       struct sockaddr_storage tproxy_addr;    /* non-local address we want to bind to for connect() */
        char *bind_hdr_name;                    /* bind to this header name if defined */
        int bind_hdr_len;                       /* length of the name of the header above */
        int bind_hdr_occ;                       /* occurrence number of header above: >0 = from first, <0 = from end, 0=disabled */
@@ -116,7 +116,7 @@ struct server {
 
        struct server *tracknext, *tracked;     /* next server in a tracking list, tracked server */
        char *trackit;                          /* temporary variable to make assignment deferrable */
-       struct sockaddr_in check_addr;          /* the address to check, if different from <addr> */
+       struct sockaddr_storage check_addr;     /* the address to check, if different from <addr> */
        short check_port;                       /* the port to use for the health checks */
        int health;                             /* 0->rise-1 = bad; rise->rise+fall-1 = good */
        int consecutive_errors;                 /* current number of consecutive errors */
index 39caf8fe724e146b63c3b9e6cb78e5d31a51160f..16a261fb5ec66212db6dc8ede389e9dace5a0564 100644 (file)
@@ -183,8 +183,8 @@ struct stream_interface {
                        struct sockaddr_storage to;     /* the address reached by the client if SN_FRT_ADDR_SET is set */
                } c; /* client side */
                struct {
-                       struct sockaddr_in from;        /* the address to spoof when connecting to the server (transparent mode) */
-                       struct sockaddr_in to;          /* the address to connect to */
+                       struct sockaddr_storage from;   /* the address to spoof when connecting to the server (transparent mode) */
+                       struct sockaddr_storage to;     /* the address to connect to */
                } s; /* server side */
        } addr; /* addresses of the remote side */
 };
index 7a9e0c6b3004a6fef236c1b9fd9e0be6aa9b1414..e2ad5b2b4c8c58adf64cfe1246714c88023df7af 100644 (file)
@@ -621,7 +621,8 @@ int assign_server(struct session *s)
        else if ((s->be->options2 & PR_O2_DISPATCH) || (s->be->options & PR_O_TRANSP)) {
                set_target_proxy(&s->target, s->be);
        }
-       else if ((s->be->options & PR_O_HTTP_PROXY) && s->req->cons->addr.s.to.sin_addr.s_addr) {
+       else if ((s->be->options & PR_O_HTTP_PROXY) &&
+                is_addr(&s->req->cons->addr.s.to)) {
                /* in proxy mode, we need a valid destination address */
                set_target_proxy(&s->target, s->be);
        }
@@ -677,7 +678,7 @@ int assign_server_address(struct session *s)
 
                s->req->cons->addr.s.to = target_srv(&s->target)->addr;
 
-               if (!s->req->cons->addr.s.to.sin_addr.s_addr) {
+               if (!is_addr(&s->req->cons->addr.s.to)) {
                        /* if the server has no address, we use the same address
                         * the client asked, which is handy for remapping ports
                         * locally on multiple addresses at once.
@@ -686,22 +687,36 @@ int assign_server_address(struct session *s)
                                get_frt_addr(s);
 
                        if (s->req->prod->addr.c.to.ss_family == AF_INET) {
-                               s->req->cons->addr.s.to.sin_addr = ((struct sockaddr_in *)&s->req->prod->addr.c.to)->sin_addr;
+                               ((struct sockaddr_in *)&s->req->cons->addr.s.to)->sin_addr = ((struct sockaddr_in *)&s->req->prod->addr.c.to)->sin_addr;
+                       } else if (s->req->prod->addr.c.to.ss_family == AF_INET6) {
+                               ((struct sockaddr_in6 *)&s->req->cons->addr.s.to)->sin6_addr = ((struct sockaddr_in6 *)&s->req->prod->addr.c.to)->sin6_addr;
                        }
                }
 
                /* if this server remaps proxied ports, we'll use
                 * the port the client connected to with an offset. */
                if (target_srv(&s->target)->state & SRV_MAPPORTS) {
+                       int base_port;
+
                        if (!(s->be->options & PR_O_TRANSP) && !(s->flags & SN_FRT_ADDR_SET))
                                get_frt_addr(s);
-                       if (s->req->prod->addr.c.to.ss_family == AF_INET) {
-                               s->req->cons->addr.s.to.sin_port = htons(ntohs(s->req->cons->addr.s.to.sin_port) +
-                                                            ntohs(((struct sockaddr_in *)&s->req->prod->addr.c.to)->sin_port));
+
+                       /* First, retrieve the port from the incoming connection */
+                       if (s->req->prod->addr.c.to.ss_family == AF_INET)
+                               base_port = ntohs(((struct sockaddr_in *)&s->req->prod->addr.c.to)->sin_port);
+                       else if (s->req->prod->addr.c.to.ss_family == AF_INET6)
+                               base_port = ntohs(((struct sockaddr_in6 *)&s->req->prod->addr.c.to)->sin6_port);
+                       else
+                               base_port = 0;
+
+                       /* Second, assign the outgoing connection's port */
+                       if (s->req->cons->addr.c.to.ss_family == AF_INET) {
+                               ((struct sockaddr_in *)&s->req->cons->addr.s.to)->sin_port =
+                                       htons(base_port + ntohs(((struct sockaddr_in *)&s->req->cons->addr.s.to)->sin_port));
                        }
                        else if (s->req->prod->addr.c.to.ss_family == AF_INET6) {
-                               s->req->cons->addr.s.to.sin_port = htons(ntohs(s->req->cons->addr.s.to.sin_port) +
-                                                            ntohs(((struct sockaddr_in6 *)&s->req->prod->addr.c.to)->sin6_port));
+                               ((struct sockaddr_in6 *)&s->req->cons->addr.s.to)->sin6_port =
+                                       htons(base_port + ntohs(((struct sockaddr_in6 *)&s->req->cons->addr.s.to)->sin6_port));
                        }
                }
        }
@@ -714,7 +729,7 @@ int assign_server_address(struct session *s)
                if (!(s->flags & SN_FRT_ADDR_SET))
                        get_frt_addr(s);
 
-               if (s->req->prod->addr.c.to.ss_family == AF_INET) {
+               if (s->req->prod->addr.c.to.ss_family == AF_INET || s->req->prod->addr.c.to.ss_family == AF_INET6) {
                        memcpy(&s->req->cons->addr.s.to, &s->req->prod->addr.c.to, MIN(sizeof(s->req->cons->addr.s.to), sizeof(s->req->prod->addr.c.to)));
                }
                /* when we support IPv6 on the backend, we may add other tests */
@@ -869,22 +884,23 @@ static void assign_tproxy_address(struct session *s)
        if (srv && srv->state & SRV_BIND_SRC) {
                switch (srv->state & SRV_TPROXY_MASK) {
                case SRV_TPROXY_ADDR:
-                       s->req->cons->addr.s.from = *(struct sockaddr_in *)&srv->tproxy_addr;
+                       s->req->cons->addr.s.from = srv->tproxy_addr;
                        break;
                case SRV_TPROXY_CLI:
                case SRV_TPROXY_CIP:
                        /* FIXME: what can we do if the client connects in IPv6 or unix socket ? */
-                       s->req->cons->addr.s.from = *(struct sockaddr_in *)&s->req->prod->addr.c.from;
+                       s->req->cons->addr.s.from = s->req->prod->addr.c.from;
                        break;
                case SRV_TPROXY_DYN:
                        if (srv->bind_hdr_occ) {
                                /* bind to the IP in a header */
-                               s->req->cons->addr.s.from.sin_port = 0;
-                               s->req->cons->addr.s.from.sin_addr.s_addr = htonl(get_ip_from_hdr2(&s->txn.req,
-                                                                               srv->bind_hdr_name,
-                                                                               srv->bind_hdr_len,
-                                                                               &s->txn.hdr_idx,
-                                                                               srv->bind_hdr_occ));
+                               ((struct sockaddr_in *)&s->req->cons->addr.s.from)->sin_port = 0;
+                               ((struct sockaddr_in *)&s->req->cons->addr.s.from)->sin_addr.s_addr =
+                                       htonl(get_ip_from_hdr2(&s->txn.req,
+                                                              srv->bind_hdr_name,
+                                                              srv->bind_hdr_len,
+                                                              &s->txn.hdr_idx,
+                                                              srv->bind_hdr_occ));
                        }
                        break;
                default:
@@ -894,22 +910,23 @@ static void assign_tproxy_address(struct session *s)
        else if (s->be->options & PR_O_BIND_SRC) {
                switch (s->be->options & PR_O_TPXY_MASK) {
                case PR_O_TPXY_ADDR:
-                       s->req->cons->addr.s.from = *(struct sockaddr_in *)&s->be->tproxy_addr;
+                       s->req->cons->addr.s.from = s->be->tproxy_addr;
                        break;
                case PR_O_TPXY_CLI:
                case PR_O_TPXY_CIP:
                        /* FIXME: what can we do if the client connects in IPv6 or socket unix? */
-                       s->req->cons->addr.s.from = *(struct sockaddr_in *)&s->req->prod->addr.c.from;
+                       s->req->cons->addr.s.from = s->req->prod->addr.c.from;
                        break;
                case PR_O_TPXY_DYN:
                        if (s->be->bind_hdr_occ) {
                                /* bind to the IP in a header */
-                               s->req->cons->addr.s.from.sin_port = 0;
-                               s->req->cons->addr.s.from.sin_addr.s_addr = htonl(get_ip_from_hdr2(&s->txn.req,
-                                                                               s->be->bind_hdr_name,
-                                                                               s->be->bind_hdr_len,
-                                                                               &s->txn.hdr_idx,
-                                                                               s->be->bind_hdr_occ));
+                               ((struct sockaddr_in *)&s->req->cons->addr.s.from)->sin_port = 0;
+                               ((struct sockaddr_in *)&s->req->cons->addr.s.from)->sin_addr.s_addr =
+                                       htonl(get_ip_from_hdr2(&s->txn.req,
+                                                              s->be->bind_hdr_name,
+                                                              s->be->bind_hdr_len,
+                                                              &s->txn.hdr_idx,
+                                                              s->be->bind_hdr_occ));
                        }
                        break;
                default:
@@ -951,7 +968,7 @@ int connect_server(struct session *s)
         * session's freshly assigned target with the stream interface's.
         */
        stream_sock_prepare_interface(s->req->cons);
-       s->req->cons->connect = tcpv4_connect_server;
+       s->req->cons->connect = tcp_connect_server;
        copy_target(&s->req->cons->target, &s->target);
 
        assign_tproxy_address(s);
index 18cfda39dbb72db5bbe7b0d3279b71accfd55149..aeec87ba2a7fff22758e490bab9639eac328b90c 100644 (file)
@@ -937,13 +937,13 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                        logsrv.u.un = *sk;
                        logsrv.u.addr.sa_family = AF_UNIX;
                } else {
-                       struct sockaddr_in *sk = str2sa(args[1]);
-                       if (!sk) {
+                       struct sockaddr_storage *sk = str2sa(args[1]);
+                       if (!sk || sk->ss_family != AF_INET) {
                                Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]);
                                err_code |= ERR_ALERT | ERR_FATAL;
                                goto out;
                        }
-                       logsrv.u.in = *sk;
+                       logsrv.u.in = *(struct sockaddr_in *)sk;
                        logsrv.u.addr.sa_family = AF_INET;
                        if (!logsrv.u.in.sin_port)
                                logsrv.u.in.sin_port = htons(SYSLOG_PORT);
@@ -1233,7 +1233,7 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm)
        else if (strcmp(args[0], "peer") == 0) { /* peer definition */
                char *rport, *raddr;
                short realport = 0;
-               struct sockaddr_in *sk;
+               struct sockaddr_storage *sk;
 
                if (!*args[2]) {
                        Alert("parsing [%s:%d] : '%s' expects <name> and <addr>[:<port>] as arguments.\n",
@@ -1287,7 +1287,15 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
                newpeer->addr = *sk;
-               newpeer->addr.sin_port = htons(realport);
+
+               switch (newpeer->addr.ss_family) {
+               case AF_INET:
+                       ((struct sockaddr_in *)&newpeer->addr)->sin_port = htons(realport);
+                       break;
+               case AF_INET6:
+                       ((struct sockaddr_in6 *)&newpeer->addr)->sin6_port = htons(realport);
+                       break;
+               }
 
                if (strcmp(newpeer->id, localpeer) == 0) {
                        /* Current is local peer, it define a frontend */
@@ -3843,7 +3851,7 @@ stats_error_parsing:
                curproxy->grace = val;
        }
        else if (!strcmp(args[0], "dispatch")) {  /* dispatch address */
-               struct sockaddr_in *sk;
+               struct sockaddr_storage *sk;
                if (curproxy == &defproxy) {
                        Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -3929,7 +3937,7 @@ stats_error_parsing:
                }
 
                if (!defsrv) {
-                       struct sockaddr_in *sk;
+                       struct sockaddr_storage *sk;
 
                        if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) {
                                Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
@@ -3975,7 +3983,15 @@ stats_error_parsing:
                                goto out;
                        }
                        newsrv->addr = *sk;
-                       newsrv->addr.sin_port = htons(realport);
+
+                       switch (newsrv->addr.ss_family) {
+                       case AF_INET:
+                               ((struct sockaddr_in *)&newsrv->addr)->sin_port = htons(realport);
+                               break;
+                       case AF_INET6:
+                               ((struct sockaddr_in6 *)&newsrv->addr)->sin6_port = htons(realport);
+                               break;
+                       }
 
                        newsrv->check_port      = curproxy->defsrv.check_port;
                        newsrv->inter           = curproxy->defsrv.inter;
@@ -4135,7 +4151,7 @@ stats_error_parsing:
                                cur_arg += 2;
                        }
                        else if (!defsrv && !strcmp(args[cur_arg], "addr")) {
-                               struct sockaddr_in *sk = str2sa(args[cur_arg + 1]);
+                               struct sockaddr_storage *sk = str2sa(args[cur_arg + 1]);
                                if (!sk) {
                                        Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]);
                                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -4280,7 +4296,7 @@ stats_error_parsing:
                        }
                        else if (!defsrv && !strcmp(args[cur_arg], "source")) {  /* address to which we bind when connecting */
                                int port_low, port_high;
-                               struct sockaddr_in *sk;
+                               struct sockaddr_storage *sk;
 
                                if (!*args[cur_arg + 1]) {
 #if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
@@ -4381,7 +4397,7 @@ stats_error_parsing:
                                                                goto out;
                                                        }
                                                } else {
-                                                       struct sockaddr_in *sk = str2sa(args[cur_arg + 1]);
+                                                       struct sockaddr_storage *sk = str2sa(args[cur_arg + 1]);
                                                        if (!sk) {
                                                                Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]);
                                                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -4458,8 +4474,16 @@ stats_error_parsing:
                                goto out;
                        }
 
-                       if (!newsrv->check_port && newsrv->check_addr.sin_port)
-                               newsrv->check_port = newsrv->check_addr.sin_port;
+                       switch (newsrv->check_addr.ss_family) {
+                               case AF_INET:
+                                       if (!newsrv->check_port && ((struct sockaddr_in *)&newsrv->check_addr)->sin_port)
+                                               newsrv->check_port = ntohs(((struct sockaddr_in *)&newsrv->check_addr)->sin_port);
+                                       break;
+                               case AF_INET6:
+                                       if (!newsrv->check_port && ((struct sockaddr_in6 *)&newsrv->check_addr)->sin6_port)
+                                               newsrv->check_port = ntohs(((struct sockaddr_in6 *)&newsrv->check_addr)->sin6_port);
+                                       break;
+                       }
 
                        if (!newsrv->check_port && !(newsrv->state & SRV_MAPPORTS))
                                newsrv->check_port = realport; /* by default */
@@ -4557,13 +4581,13 @@ stats_error_parsing:
                                logsrv.u.un = *sk;
                                logsrv.u.addr.sa_family = AF_UNIX;
                        } else {
-                               struct sockaddr_in *sk = str2sa(args[1]);
-                               if (!sk) {
+                               struct sockaddr_storage *sk = str2sa(args[1]);
+                               if (!sk || sk->ss_family != AF_INET) {
                                        Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]);
                                        err_code |= ERR_ALERT | ERR_FATAL;
                                        goto out;
                                }
-                               logsrv.u.in = *sk;
+                               logsrv.u.in = *(struct sockaddr_in *)sk;
                                logsrv.u.addr.sa_family = AF_INET;
                                if (!logsrv.u.in.sin_port) {
                                        logsrv.u.in.sin_port =
@@ -4598,7 +4622,7 @@ stats_error_parsing:
        }
        else if (!strcmp(args[0], "source")) {  /* address to which we bind when connecting */
                int cur_arg;
-               struct sockaddr_in *sk;
+               struct sockaddr_storage *sk;
 
                if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
                        err_code |= ERR_WARN;
@@ -4690,7 +4714,7 @@ stats_error_parsing:
                                                goto out;
                                        }
                                } else {
-                                       struct sockaddr_in *sk = str2sa(args[cur_arg + 1]);
+                                       struct sockaddr_storage *sk = str2sa(args[cur_arg + 1]);
                                        if (!sk) {
                                                Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]);
                                                err_code |= ERR_ALERT | ERR_FATAL;
index ba3e745e9c05db08d5592e2854d0a3be1285c289..e4982ca5a00d17a457f294cad696d9aaee45090c 100644 (file)
@@ -810,10 +810,21 @@ static int event_srv_chk_w(int fd)
                         *  - connected (EISCONN, 0)
                         */
 
-                       struct sockaddr_in sa;
+                       struct sockaddr_storage sa;
 
-                       sa = (s->check_addr.sin_addr.s_addr) ? s->check_addr : s->addr;
-                       sa.sin_port = htons(s->check_port);
+                       if (is_addr(&s->check_addr))
+                               sa = s->check_addr;
+                       else
+                               sa = s->addr;
+
+                       switch (s->check_addr.ss_family) {
+                       case AF_INET:
+                               ((struct sockaddr_in *)&sa)->sin_port = htons(s->check_port);
+                               break;
+                       case AF_INET6:
+                               ((struct sockaddr_in6 *)&sa)->sin6_port = htons(s->check_port);
+                               break;
+                       }
 
                        if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == 0)
                                errno = 0;
@@ -1193,7 +1204,7 @@ struct task *process_chk(struct task *t)
 {
        int attempts = 0;
        struct server *s = t->context;
-       struct sockaddr_in sa;
+       struct sockaddr_storage sa;
        int fd;
        int rv;
 
@@ -1223,7 +1234,7 @@ struct task *process_chk(struct task *t)
 
                /* we'll initiate a new check */
                set_server_check_status(s, HCHK_STATUS_START, NULL);
-               if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
+               if ((fd = socket(s->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) != -1) {
                        if ((fd < global.maxsock) &&
                            (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
                            (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != -1)) {
@@ -1233,28 +1244,35 @@ struct task *process_chk(struct task *t)
                                        /* We don't want to useless data */
                                        setsockopt(fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger));
                                }
-                               
-                               if (s->check_addr.sin_addr.s_addr)
+
+                               if (is_addr(&s->check_addr))
                                        /* we'll connect to the check addr specified on the server */
                                        sa = s->check_addr;
                                else
                                        /* we'll connect to the addr on the server */
                                        sa = s->addr;
 
-                               /* we'll connect to the check port on the server */
-                               sa.sin_port = htons(s->check_port);
-
+                               switch (s->check_addr.ss_family) {
+                               case AF_INET:
+                                       /* we'll connect to the check port on the server */
+                                       ((struct sockaddr_in *)&sa)->sin_port = htons(s->check_port);
+                                       break;
+                               case AF_INET6:
+                                       /* we'll connect to the check port on the server */
+                                       ((struct sockaddr_in6 *)&sa)->sin6_port = htons(s->check_port);
+                                       break;
+                               }
                                /* allow specific binding :
                                 * - server-specific at first
                                 * - proxy-specific next
                                 */
                                if (s->state & SRV_BIND_SRC) {
-                                       struct sockaddr_in *remote = NULL;
+                                       struct sockaddr_storage *remote = NULL;
                                        int ret, flags = 0;
 
 #if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
                                        if ((s->state & SRV_TPROXY_MASK) == SRV_TPROXY_ADDR) {
-                                               remote = (struct sockaddr_in *)&s->tproxy_addr;
+                                               remote = &s->tproxy_addr;
                                                flags  = 3;
                                        }
 #endif
@@ -1266,7 +1284,7 @@ struct task *process_chk(struct task *t)
 #endif
                                        if (s->sport_range) {
                                                int bind_attempts = 10; /* should be more than enough to find a spare port */
-                                               struct sockaddr_in src;
+                                               struct sockaddr_storage src;
 
                                                ret = 1;
                                                src = s->source_addr;
@@ -1287,13 +1305,21 @@ struct task *process_chk(struct task *t)
                                                                break;
 
                                                        fdinfo[fd].port_range = s->sport_range;
-                                                       src.sin_port = htons(fdinfo[fd].local_port);
 
-                                                       ret = tcpv4_bind_socket(fd, flags, &src, remote);
+                                                       switch (src.ss_family) {
+                                                       case AF_INET:
+                                                               ((struct sockaddr_in *)&src)->sin_port = htons(fdinfo[fd].local_port);
+                                                               break;
+                                                       case AF_INET6:
+                                                               ((struct sockaddr_in6 *)&src)->sin6_port = htons(fdinfo[fd].local_port);
+                                                               break;
+                                                       }
+
+                                                       ret = tcp_bind_socket(fd, flags, &src, remote);
                                                } while (ret != 0); /* binding NOK */
                                        }
                                        else {
-                                               ret = tcpv4_bind_socket(fd, flags, &s->source_addr, remote);
+                                               ret = tcp_bind_socket(fd, flags, &s->source_addr, remote);
                                        }
 
                                        if (ret) {
@@ -1311,12 +1337,12 @@ struct task *process_chk(struct task *t)
                                        }
                                }
                                else if (s->proxy->options & PR_O_BIND_SRC) {
-                                       struct sockaddr_in *remote = NULL;
+                                       struct sockaddr_storage *remote = NULL;
                                        int ret, flags = 0;
 
 #if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
                                        if ((s->proxy->options & PR_O_TPXY_MASK) == PR_O_TPXY_ADDR) {
-                                               remote = (struct sockaddr_in *)&s->proxy->tproxy_addr;
+                                               remote = &s->proxy->tproxy_addr;
                                                flags  = 3;
                                        }
 #endif
@@ -1326,7 +1352,7 @@ struct task *process_chk(struct task *t)
                                                setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
                                                           s->proxy->iface_name, s->proxy->iface_len + 1);
 #endif
-                                       ret = tcpv4_bind_socket(fd, flags, &s->proxy->source_addr, remote);
+                                       ret = tcp_bind_socket(fd, flags, &s->proxy->source_addr, remote);
                                        if (ret) {
                                                set_server_check_status(s, HCHK_STATUS_SOCKERR, NULL);
                                                switch (ret) {
index ed577ad670a0b723e43bec672ea47a972eb5e1c8..b04b297fadd2a22ea9c49adadc44b24f281ad7c5 100644 (file)
@@ -2111,10 +2111,20 @@ int stats_dump_proxy(struct stream_interface *si, struct proxy *px, struct uri_a
                                        chunk_printf(&msg, " title=\"IP: ");
 
                                        /* IP */
-                                       if (inet_ntop(sv->addr.sin_family, &sv->addr.sin_addr, str, sizeof(str)))
-                                               chunk_printf(&msg, "%s:%d", str, htons(sv->addr.sin_port));
-                                       else
-                                               chunk_printf(&msg, "(%s)", strerror(errno));
+                                       switch (sv->addr.ss_family) {
+                                       case AF_INET:
+                                               if (inet_ntop(AF_INET, (const void *)&((struct sockaddr_in *)&sv->addr)->sin_addr, str, sizeof(str)))
+                                                       chunk_printf(&msg, "%s:%d", str, htons(((struct sockaddr_in *)&sv->addr)->sin_port));
+                                               else
+                                                       chunk_printf(&msg, "(%s)", strerror(errno));
+                                               break;
+                                       case AF_INET6:
+                                               if (inet_ntop(AF_INET6, (const void *)&((struct sockaddr_in6 *)&sv->addr)->sin6_addr, str, sizeof(str)))
+                                                       chunk_printf(&msg, "%s:%d", str, htons(((struct sockaddr_in6 *)&sv->addr)->sin6_port));
+                                               else
+                                                       chunk_printf(&msg, "(%s)", strerror(errno));
+                                               break;
+                                       }
 
                                        /* id */
                                        chunk_printf(&msg, ", id: %d", sv->puid);
index 5b8e7490abfbecf421ea771cb8aa4b1e6265e632..739c09b05df4ebbdb591d9f68293894b54256c49 100644 (file)
@@ -1174,7 +1174,7 @@ struct session *peer_session_create(struct peer *peer, struct peer_session *ps)
        s->si[1].conn_retries = p->conn_retries;
        s->si[1].err_type = SI_ET_NONE;
        s->si[1].err_loc = NULL;
-       s->si[1].connect = tcpv4_connect_server;
+       s->si[1].connect = tcp_connect_server;
        set_target_proxy(&s->si[1].target, s->be);
        s->si[1].exp = TICK_ETERNITY;
        s->si[1].flags = SI_FL_NONE;
index cbfdca2877cd78f5d649cc60cfdcd87c1010f076..ff2f44cac34f9cd088f6315fdff6515f8f2935b3 100644 (file)
@@ -8037,9 +8037,9 @@ acl_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, char *sol,
                test->flags |= ACL_TEST_F_FETCH_MORE;
                test->flags |= ACL_TEST_F_VOL_HDR;
                /* Same optimization as url_ip */
-               memset(&l4->req->cons->addr.s.to.sin_addr, 0, sizeof(l4->req->cons->addr.s.to.sin_addr));
-               url2ip((char *)ctx->line + ctx->val, &l4->req->cons->addr.s.to.sin_addr);
-               test->ptr = (void *)&l4->req->cons->addr.s.to.sin_addr;
+               memset(&((struct sockaddr_in *)&l4->req->cons->addr.s.to)->sin_addr, 0, sizeof(((struct sockaddr_in *)&l4->req->cons->addr.s.to)->sin_addr));
+               url2ipv4((char *)ctx->line + ctx->val, &((struct sockaddr_in *)&l4->req->cons->addr.s.to)->sin_addr);
+               test->ptr = (void *)&((struct sockaddr_in *)&l4->req->cons->addr.s.to)->sin_addr;
                test->i = AF_INET;
                return 1;
        }
index 2d79e22d26135dc993e8af8db3a4216531151f6b..04562f10472994bc55302c2cfaff0257d8b4ccf9 100644 (file)
@@ -100,7 +100,7 @@ static struct protocol proto_tcpv6 = {
 };
 
 
-/* Binds ipv4 address <local> to socket <fd>, unless <flags> is set, in which
+/* Binds ipv4/ipv6 address <local> to socket <fd>, unless <flags> is set, in which
  * case we try to bind <remote>. <flags> is a 2-bit field consisting of :
  *  - 0 : ignore remote address (may even be a NULL pointer)
  *  - 1 : use provided address
@@ -114,9 +114,9 @@ static struct protocol proto_tcpv6 = {
  * This function returns 0 when everything's OK, 1 if it could not bind, to the
  * local address, 2 if it could not bind to the foreign address.
  */
-int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote)
+int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct sockaddr_storage *remote)
 {
-       struct sockaddr_in bind_addr;
+       struct sockaddr_storage bind_addr;
        int foreign_ok = 0;
        int ret;
 
@@ -132,10 +132,20 @@ int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct socka
 #endif
        if (flags) {
                memset(&bind_addr, 0, sizeof(bind_addr));
-               if (flags & 1)
-                       bind_addr.sin_addr = remote->sin_addr;
-               if (flags & 2)
-                       bind_addr.sin_port = remote->sin_port;
+               switch (remote->ss_family) {
+               case AF_INET:
+                       if (flags & 1)
+                               ((struct sockaddr_in *)&bind_addr)->sin_addr = ((struct sockaddr_in *)remote)->sin_addr;
+                       if (flags & 2)
+                               ((struct sockaddr_in *)&bind_addr)->sin_port = ((struct sockaddr_in *)remote)->sin_port;
+                       break;
+               case AF_INET6:
+                       if (flags & 1)
+                               ((struct sockaddr_in6 *)&bind_addr)->sin6_addr = ((struct sockaddr_in6 *)remote)->sin6_addr;
+                       if (flags & 2)
+                               ((struct sockaddr_in6 *)&bind_addr)->sin6_port = ((struct sockaddr_in6 *)remote)->sin6_port;
+                       break;
+               }
        }
 
        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one));
@@ -198,7 +208,7 @@ int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct socka
  * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
  */
 
-int tcpv4_connect_server(struct stream_interface *si)
+int tcp_connect_server(struct stream_interface *si)
 {
        int fd;
        struct server *srv;
@@ -217,7 +227,7 @@ int tcpv4_connect_server(struct stream_interface *si)
                return SN_ERR_INTERNAL;
        }
 
-       if ((fd = si->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+       if ((fd = si->fd = socket(si->addr.s.to.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
                qfprintf(stderr, "Cannot get a server socket.\n");
 
                if (errno == ENFILE)
@@ -284,7 +294,7 @@ int tcpv4_connect_server(struct stream_interface *si)
 
                if (srv->sport_range) {
                        int attempts = 10; /* should be more than enough to find a spare port */
-                       struct sockaddr_in src;
+                       struct sockaddr_storage src;
 
                        ret = 1;
                        src = srv->source_addr;
@@ -305,13 +315,20 @@ int tcpv4_connect_server(struct stream_interface *si)
                                        break;
 
                                fdinfo[fd].port_range = srv->sport_range;
-                               src.sin_port = htons(fdinfo[fd].local_port);
+                               switch (src.ss_family) {
+                               case AF_INET:
+                                       ((struct sockaddr_in *)&src)->sin_port = htons(fdinfo[fd].local_port);
+                                       break;
+                               case AF_INET6:
+                                       ((struct sockaddr_in6 *)&src)->sin6_port = htons(fdinfo[fd].local_port);
+                                       break;
+                               }
 
-                               ret = tcpv4_bind_socket(fd, flags, &src, (struct sockaddr_in *)&si->addr.s.from);
+                               ret = tcp_bind_socket(fd, flags, &src, &si->addr.s.from);
                        } while (ret != 0); /* binding NOK */
                }
                else {
-                       ret = tcpv4_bind_socket(fd, flags, &srv->source_addr, (struct sockaddr_in *)&si->addr.s.from);
+                       ret = tcp_bind_socket(fd, flags, &srv->source_addr, &si->addr.s.from);
                }
 
                if (ret) {
@@ -354,7 +371,7 @@ int tcpv4_connect_server(struct stream_interface *si)
                if (be->iface_name)
                        setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, be->iface_name, be->iface_len + 1);
 #endif
-               ret = tcpv4_bind_socket(fd, flags, &be->source_addr, (struct sockaddr_in *)&si->addr.s.from);
+               ret = tcp_bind_socket(fd, flags, &be->source_addr, &si->addr.s.from);
                if (ret) {
                        close(fd);
                        if (ret == 1) {
@@ -389,7 +406,7 @@ int tcpv4_connect_server(struct stream_interface *si)
        if (global.tune.server_rcvbuf)
                 setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &global.tune.server_rcvbuf, sizeof(global.tune.server_rcvbuf));
 
-       if ((connect(fd, (struct sockaddr *)&si->addr.s.to, sizeof(struct sockaddr_in)) == -1) &&
+       if ((connect(fd, (struct sockaddr *)&si->addr.s.to, sizeof(struct sockaddr_storage)) == -1) &&
            (errno != EINPROGRESS) && (errno != EALREADY) && (errno != EISCONN)) {
 
                if (errno == EAGAIN || errno == EADDRINUSE) {
@@ -432,7 +449,7 @@ int tcpv4_connect_server(struct stream_interface *si)
        fdtab[fd].cb[DIR_WR].b = si->ob;
 
        fdinfo[fd].peeraddr = (struct sockaddr *)&si->addr.s.to;
-       fdinfo[fd].peerlen = sizeof(struct sockaddr_in);
+       fdinfo[fd].peerlen = sizeof(struct sockaddr_storage);
 
        fd_insert(fd);
        EV_FD_SET(fd, DIR_WR);  /* for connect status */
index 1ab2194128f87baa4172c12506d6e83ecb7e59ae..27fa374eac68d255934fd952a981e30fd5268cb2 100644 (file)
@@ -219,10 +219,10 @@ const char *invalid_domainchar(const char *name) {
  * a host name, or empty or "*" to indicate INADDR_ANY. NULL is returned
  * if the host part cannot be resolved.
  */
-struct sockaddr_in *str2sa(char *str)
+struct sockaddr_storage *str2sa(char *str)
 {
-       static struct sockaddr_in sa;
-       struct sockaddr_in *ret = NULL;
+       static struct sockaddr_storage sa;
+       struct sockaddr_storage *ret = NULL;
        char *c;
        int port;
 
@@ -238,17 +238,17 @@ struct sockaddr_in *str2sa(char *str)
        else
                port = 0;
 
+       sa.ss_family = AF_INET;
+       ((struct sockaddr_in *)&sa)->sin_port = htons(port);
        if (*str == '*' || *str == '\0') { /* INADDR_ANY */
-               sa.sin_addr.s_addr = INADDR_ANY;
+               ((struct sockaddr_in *)&sa)->sin_addr.s_addr = INADDR_ANY;
        }
-       else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
+       else if (!inet_pton(sa.ss_family, str, &((struct sockaddr_in *)&sa)->sin_addr)) {
                struct hostent *he = gethostbyname(str);
                if (!he)
                        goto out;
-               sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
+               ((struct sockaddr_in *)&sa)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
        }
-       sa.sin_port   = htons(port);
-       sa.sin_family = AF_INET;
        ret = &sa;
  out:
        free(str);
@@ -265,10 +265,10 @@ struct sockaddr_in *str2sa(char *str)
  * name, or empty or "*" to indicate INADDR_ANY. NULL is returned if the host
  * part cannot be resolved.
  */
-struct sockaddr_in *str2sa_range(char *str, int *low, int *high)
+struct sockaddr_storage *str2sa_range(char *str, int *low, int *high)
 {
-       static struct sockaddr_in sa;
-       struct sockaddr_in *ret = NULL;
+       static struct sockaddr_storage sa;
+       struct sockaddr_storage *ret = NULL;
        char *c;
        int portl, porth;
 
@@ -293,17 +293,17 @@ struct sockaddr_in *str2sa_range(char *str, int *low, int *high)
                porth = 0;
        }
 
+       sa.ss_family = AF_INET;
+       ((struct sockaddr_in *)&sa)->sin_port = htonl(portl);
        if (*str == '*' || *str == '\0') { /* INADDR_ANY */
-               sa.sin_addr.s_addr = INADDR_ANY;
+               ((struct sockaddr_in *)&sa)->sin_addr.s_addr = INADDR_ANY;
        }
-       else if (!inet_pton(AF_INET, str, &sa.sin_addr)) {
+       else if (!inet_pton(sa.ss_family, str, &((struct sockaddr_in *)&sa)->sin_addr)) {
                struct hostent *he = gethostbyname(str);
                if (!he)
                        goto out;
-               sa.sin_addr = *(struct in_addr *) *(he->h_addr_list);
+               ((struct sockaddr_in *)&sa)->sin_addr = *(struct in_addr *) *(he->h_addr_list);
        }
-       sa.sin_port   = htons(portl);
-       sa.sin_family = AF_INET;
        ret = &sa;
 
        *low = portl;
@@ -387,9 +387,9 @@ int str2net(const char *str, struct in_addr *addr, struct in_addr *mask)
 
 
 /*
- * Parse IP address found in url.
+ * Parse IPv4 address found in url.
  */
-int url2ip(const char *addr, struct in_addr *dst)
+int url2ipv4(const char *addr, struct in_addr *dst)
 {
        int saw_digit, octets, ch;
        u_char tmp[4], *tp;
@@ -430,18 +430,20 @@ int url2ip(const char *addr, struct in_addr *dst)
 }
 
 /*
- * Resolve destination server from URL. Convert <str> to a sockaddr_in*.
+ * Resolve destination server from URL. Convert <str> to a sockaddr_storage*.
  */
-int url2sa(const char *url, int ulen, struct sockaddr_in *addr)
+int url2sa(const char *url, int ulen, struct sockaddr_storage *addr)
 {
        const char *curr = url, *cp = url;
        int ret, url_code = 0;
        unsigned int http_code = 0;
 
        /* Cleanup the room */
-       addr->sin_family = AF_INET;
-       addr->sin_addr.s_addr = 0;
-       addr->sin_port = 0;
+
+       /* FIXME: assume IPv4 only for now */
+       ((struct sockaddr_in *)addr)->sin_family = AF_INET;
+       ((struct sockaddr_in *)addr)->sin_addr.s_addr = 0;
+       ((struct sockaddr_in *)addr)->sin_port = 0;
 
        /* Firstly, try to find :// pattern */
        while (curr < url+ulen && url_code != 0x3a2f2f) {
@@ -467,12 +469,12 @@ int url2sa(const char *url, int ulen, struct sockaddr_in *addr)
                         * be warned this can slow down global daemon performances
                         * while handling lagging dns responses.
                         */
-                       ret = url2ip(curr, &addr->sin_addr);
+                       ret = url2ipv4(curr, &((struct sockaddr_in *)&addr)->sin_addr);
                        if (!ret)
                                return -1;
                        curr += ret;
-                       addr->sin_port = (*curr == ':') ? str2uic(++curr) : 80;
-                       addr->sin_port = htons(addr->sin_port);
+                       ((struct sockaddr_in *)addr)->sin_port = (*curr == ':') ? str2uic(++curr) : 80;
+                       ((struct sockaddr_in *)addr)->sin_port = htons(((struct sockaddr_in *)&addr)->sin_port);
                }
                return 0;
        }