/*
- include/proto/proto_tcp.h
- This file contains TCP socket protocol definitions.
-
- Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation, version 2.1
- exclusively.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*/
+ * include/proto/proto_tcp.h
+ * This file contains TCP socket protocol definitions.
+ *
+ * Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
#ifndef _PROTO_PROTO_TCP_H
#define _PROTO_PROTO_TCP_H
int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen);
int tcpv4_connect_server(struct stream_interface *si,
struct proxy *be, struct server *srv,
- struct sockaddr *srv_addr, struct sockaddr *cli_addr);
+ struct sockaddr *srv_addr, struct sockaddr *from_addr);
int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit);
int acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
struct acl_expr *expr, struct acl_test *test);
struct sockaddr_storage cli_addr; /* the client address */
struct sockaddr_storage frt_addr; /* the frontend address reached by the client if SN_FRT_ADDR_SET is set */
struct sockaddr_in srv_addr; /* the address to connect to */
+ struct sockaddr_in from_addr; /* the address to spoof when connecting to the server (transparent mode) */
struct server *srv; /* the server the session will be running or has been running on */
struct server *srv_conn; /* session already has a slot on a server and is not in queue */
struct server *prev_srv; /* the server the was running on, after a redispatch, otherwise NULL */
}
}
+/* If an explicit source binding is specified on the server and/or backend, and
+ * this source makes use of the transparent proxy, then it is extracted now and
+ * assigned to the session's from_addr entry.
+ */
+static void assign_tproxy_address(struct session *s)
+{
+#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
+ if (s->srv != NULL && s->srv->state & SRV_BIND_SRC) {
+ switch (s->srv->state & SRV_TPROXY_MASK) {
+ case SRV_TPROXY_ADDR:
+ s->from_addr = *(struct sockaddr_in *)&s->srv->tproxy_addr;
+ break;
+ case SRV_TPROXY_CLI:
+ case SRV_TPROXY_CIP:
+ /* FIXME: what can we do if the client connects in IPv6 ? */
+ s->from_addr = *(struct sockaddr_in *)&s->cli_addr;
+ break;
+ default:
+ s->from_addr = *(struct sockaddr_in *)0;
+ }
+ }
+ else if (s->be->options & PR_O_BIND_SRC) {
+ switch (s->be->options & PR_O_TPXY_MASK) {
+ case PR_O_TPXY_ADDR:
+ s->from_addr = *(struct sockaddr_in *)&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 ? */
+ s->from_addr = *(struct sockaddr_in *)&s->cli_addr;
+ break;
+ default:
+ s->from_addr = *(struct sockaddr_in *)0;
+ }
+ }
+#endif
+}
+
+
/*
* This function initiates a connection to the server assigned to this session
* (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
if (!s->req->cons->connect)
return SN_ERR_INTERNAL;
+ assign_tproxy_address(s);
+
err = s->req->cons->connect(s->req->cons, s->be, s->srv,
(struct sockaddr *)&s->srv_addr,
- (struct sockaddr *)&s->cli_addr);
+ (struct sockaddr *)&s->from_addr);
if (err != SN_ERR_NONE)
return err;
/*
* This function initiates a connection to the server assigned to this session
- * (s->srv, s->srv_addr). It will assign a server if none is assigned yet.
+ * (s->srv, s->srv_addr). It will assign a server if none is assigned yet. A
+ * source address may be pointed to by <from_addr>. Note that this is only used
+ * in case of transparent proxying. Normal source bind addresses are still
+ * determined locally (due to the possible need of a source port).
+ *
* It can return one of :
* - SN_ERR_NONE if everything's OK
* - SN_ERR_SRVTO if there are no more servers
*/
int tcpv4_connect_server(struct stream_interface *si,
struct proxy *be, struct server *srv,
- struct sockaddr *srv_addr, struct sockaddr *cli_addr)
+ struct sockaddr *srv_addr, struct sockaddr *from_addr)
{
int fd;
* - proxy-specific next
*/
if (srv != NULL && srv->state & SRV_BIND_SRC) {
- struct sockaddr_in *remote = NULL;
int ret, flags = 0;
-#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
switch (srv->state & SRV_TPROXY_MASK) {
case SRV_TPROXY_ADDR:
- remote = (struct sockaddr_in *)&srv->tproxy_addr;
- flags = 3;
- break;
case SRV_TPROXY_CLI:
- if (cli_addr)
- flags |= 2;
- /* fall through */
+ flags = 3;
+ break;
case SRV_TPROXY_CIP:
- /* FIXME: what can we do if the client connects in IPv6 ? */
- if (cli_addr)
- flags |= 1;
- remote = (struct sockaddr_in *)cli_addr;
+ flags = 1;
break;
}
-#endif
+
#ifdef SO_BINDTODEVICE
/* Note: this might fail if not CAP_NET_RAW */
if (srv->iface_name)
fdinfo[fd].port_range = srv->sport_range;
src.sin_port = htons(fdinfo[fd].local_port);
- ret = tcpv4_bind_socket(fd, flags, &src, remote);
+ ret = tcpv4_bind_socket(fd, flags, &src, (struct sockaddr_in *)from_addr);
} while (ret != 0); /* binding NOK */
}
else {
- ret = tcpv4_bind_socket(fd, flags, &srv->source_addr, remote);
+ ret = tcpv4_bind_socket(fd, flags, &srv->source_addr, (struct sockaddr_in *)from_addr);
}
if (ret) {
}
}
else if (be->options & PR_O_BIND_SRC) {
- struct sockaddr_in *remote = NULL;
int ret, flags = 0;
-#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY)
switch (be->options & PR_O_TPXY_MASK) {
case PR_O_TPXY_ADDR:
- remote = (struct sockaddr_in *)&be->tproxy_addr;
- flags = 3;
- break;
case PR_O_TPXY_CLI:
- if (cli_addr)
- flags |= 2;
- /* fall through */
+ flags = 3;
+ break;
case PR_O_TPXY_CIP:
- /* FIXME: what can we do if the client connects in IPv6 ? */
- if (cli_addr)
- flags |= 1;
- remote = (struct sockaddr_in *)cli_addr;
+ flags = 1;
break;
}
-#endif
+
#ifdef SO_BINDTODEVICE
/* Note: this might fail if not CAP_NET_RAW */
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, remote);
+ ret = tcpv4_bind_socket(fd, flags, &be->source_addr, (struct sockaddr_in *)from_addr);
if (ret) {
close(fd);
if (ret == 1) {