* 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
* "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
/*
* 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)
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 */
#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);
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 */
};
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 */
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 */
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 */
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 */
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 */
};
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);
}
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.
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));
}
}
}
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 */
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:
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:
* 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);
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);
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",
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 */
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;
}
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);
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;
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;
}
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)
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;
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 */
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 =
}
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;
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;
* - 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;
{
int attempts = 0;
struct server *s = t->context;
- struct sockaddr_in sa;
+ struct sockaddr_storage sa;
int fd;
int rv;
/* 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)) {
/* 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
#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;
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) {
}
}
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
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) {
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);
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;
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;
}
};
-/* 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
* 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;
#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));
* 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;
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)
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;
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) {
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) {
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) {
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 */
* 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;
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);
* 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;
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;
/*
- * 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;
}
/*
- * 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) {
* 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;
}